Giter Club home page Giter Club logo

codinginterviewchinese2's People

Contributors

zhedahht avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

codinginterviewchinese2's Issues

剪绳子代码是否与题目描述不符

这道题目有问题,题目说的是:给你一根长度为n的绳子,请把绳子剪成m段,求最大值,而解法却是剪任意段求最大值,并没有限制剪的段数。

比如一段绳子长度为 7,要求剪成 7段,那么答案就不是12 了,12是绳子能剪成的最大长度,但只有剪成2段或者3段才能得到12,剪成7段长度不可能为12。

代码的解法是不限制绳子的段数的,或许是我没有理解清楚代码,还请解惑

面试题1考虑异常安全的解法有误

代码仓库没有给出,书上给出了

//copy operator
CMyString& CMyString::operator=(const CMyString& str)
{
	if(m_pData != &str)
	{
		CMyString tmpData(str);
		
		char *ptmp = tmpData.m_pData;
		tmpData.m_pData = m_pData;
		m_pData = ptmp;
	}
	return *this;
}

m_pData是private的,书上写的有点问题

Utilities目录中的Tree.cpp有一处错误

在PrintTreeNode(const TreeNode* pNode)函数中,遗漏了一句++i;,如下:

void PrintTreeNode(const TreeNode* pNode)
{
	if (pNode != nullptr)
	{
		printf("value of this node is: %d.\n", pNode->m_nValue);

		printf("its children is as the following:\n");
		std::vector<TreeNode*>::const_iterator i = pNode->m_vChildren.begin();
		while (i < pNode->m_vChildren.end())
		{
			if (*i != nullptr)
			{
				printf("%d\t", (*i)->m_nValue);
				++i;       //此句不加会导致程序进入死循环
			}
			printf("%d\t", (*i)->m_nValue);
		}

		printf("\n");
	}
	else
	{
		printf("this node is nullptr.\n");
	}

	printf("\n");
}

面试题42:连续子数组的最大和。我有更简洁的实现法,思路是类似的,求大神看一眼,我就满足了。


/**
 * 题目:输入一个整型数组,数组里有正数也有负数。数组中的一个或
 * 连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复
 * 杂度为 O(n)。
 *
 * @author flying
 */
public class Q42_MaxSubSequence {
    /**
     * 1. 把数组的变化,看作是连绵起伏的山谷。连续的非负数序列是一段山,连续的负数序列是一段谷,山谷交错。
     * 2. 山和谷都以自己最右侧的坐标命名,记作 n
     * 2. 如果只有一段山 n,那么最大值就是这段山的面积 sum(n)。
     * 3. 在一段山的基础上添加谷 n,那么最大值是 sun(山n) 的面积, 然后把这段山谷整合起来成为一段山,整合后的山的面积是:
     *      sum(山-谷) > 0  ? sum(山-谷) : 0;, 这个记作 sum'(n), sum'(n) 不等于 sum(n), sum(n)
     * 4. 这样的话,长度为 n 的山谷序列中,最大值连续序列 max_n = max(max(n-1), sum(n) + sum'(n -1))。
     * 5. 从第一段开始求,一直递推到 第 n 段,可以在 o(n) 的时间内搞定。
     * 为了让代码看上去行数更少,我合并了一些连续的赋值运算,以及省略掉了大括号。
     */
    private int maxSubSequence(int[] array) {
        if (array == null)
            throw new IllegalArgumentException("param is invalid");

        int max = 0, sumMount = 0;

        for (int i : array)
            max = Math.max(max, sumMount = Math.max(0, sumMount + i));

        return max;
    }

    public void test() {
        System.out.println(maxSubSequence(new int[] {1}));
        System.out.println(maxSubSequence(new int[] {0}));
        System.out.println(maxSubSequence(new int[] {-1, -2, -3, -4, -5}));
        System.out.println(maxSubSequence(new int[] {1, -2, 3, 10, -4, 7, 2, -5}));
    }
}

面试题5:替换空格

现在给出的实现如下:

/*length 为字符数组str的总容量,大于或等于字符串str的实际长度*/
void ReplaceBlank(char str[], int length)
{
    if(str == nullptr && length <= 0)
        return;

    /*originalLength 为字符串str的实际长度*/
    int originalLength = 0;
    int numberOfBlank = 0;
    int i = 0;
    while(str[i] != '\0')
    {
        ++ originalLength;

        if(str[i] == ' ')
            ++ numberOfBlank;

        ++ i;
    }

    /*newLength 为把空格替换成'%20'之后的长度*/
    int newLength = originalLength + numberOfBlank * 2;
    if(newLength > length)
        return;

    int indexOfOriginal = originalLength;
    int indexOfNew = newLength;
    while(indexOfOriginal >= 0 && indexOfNew > indexOfOriginal)
    {
        if(str[indexOfOriginal] == ' ')
        {
            str[indexOfNew --] = '0';
            str[indexOfNew --] = '2';
            str[indexOfNew --] = '%';
        }
        else
        {
            str[indexOfNew --] = str[indexOfOriginal];
        }

        -- indexOfOriginal;
    }
}

我的考虑是 originalLength 的计算,在 strlen(string) 时,确实像上面的计算长度是没有错的,不用考虑字符数组最后的空字符 \0,在这里的话,考虑边界条件,个人觉得应该添加如下改动:

  1. 在计算 newLength 之前,将 originalLength 给多计算一个字符,算上最后的空字符 \0,其他的保持不变即可;
  2. 如果考虑和 strlen(string) 一样的语义,在计算 originalLength 时就用如上的代码计算长度即可,但在判断得到的 newLength 是否超出 length 时,需要
    if(newLength +> length)
        return;

这样保证替换之后的字符串的最后一位空字符是字符数组提供的,在测试时,传入的字符数组是 char str[100] = "We are happy.",其13-99索引号均填充为 \0

以上 1 和 2 两种方案选择一种即可。

关于面试题45中的一行代码

PrintMinNumber函数中
char** strNumbers = (char**)(new int[length])
我在mac上编译运行的时候当数组个数大于4时会结果会出现乱码,我将其改成
char** strNumbers = new char*[length]
后代码输出结果正确。
求解释。

面试题第三题1

我有点疑惑为什么要用两层while循环,第二层的while改为if会不会更好一点,因为第二层只是一个判断并不会进入循环

面试题43:分析过程错误

作者在面试题43有这样的分析,存在错误——“可以再把1346-21345分成两段:[1346, 11345]和[11346, 21345].每一段剩下的4位数字中,选择其中一位是1,其余三位可以在0~9这10个数字任意选择,因此根据排列组合原则,总共出现的次数是2x4x10^3 = 8000次”

按作者说的,剩下的4位数字中,如果前3位选0,最后一位选1,数字1应当包含在8000次里面,但是数字1并不在 [1346, 11345]和[11346, 21345] 任一区间内,很明显上述分析并不对

面试题6 从未到头打印链表

编译有问题:
1>------ 已启动生成: 项目: test3, 配置: Debug Win32 ------
1>生成启动时间为 2018/5/25 16:18:47。
1>InitializeBuildStatus:
1> 正在对“Debug\test3.unsuccessfulbuild”执行 Touch 任务。
1>ClCompile:
1> 所有输出均为最新。
1>PrintListInReversedOrder.obj : error LNK2019: 无法解析的外部符号 "void __cdecl PrintList(struct ListNode *)" (?PrintList@@YAXPAUListNode@@@z),该符号在函数 "void __cdecl Test(struct ListNode *)" (?Test@@YAXPAUListNode@@@z) 中被引用
1>PrintListInReversedOrder.obj : error LNK2019: 无法解析的外部符号 "void __cdecl DestroyList(struct ListNode *)" (?DestroyList@@YAXPAUListNode@@@z),该符号在函数 "void __cdecl Test1(void)" (?Test1@@yaxxz) 中被引用
1>PrintListInReversedOrder.obj : error LNK2019: 无法解析的外部符号 "void __cdecl ConnectListNodes(struct ListNode *,struct ListNode *)" (?ConnectListNodes@@YAXPAUListNode@@0@Z),该符号在函数 "void __cdecl Test1(void)" (?Test1@@yaxxz) 中被引用
1>PrintListInReversedOrder.obj : error LNK2019: 无法解析的外部符号 "struct ListNode * __cdecl CreateListNode(int)" (?CreateListNode@@YAPAUListNode@@h@Z),该符号在函数 "void __cdecl Test1(void)" (?Test1@@yaxxz) 中被引用
1>G:\visual studio 2010\Projects\test3\Debug\test3.exe : fatal error LNK1120: 4 个无法解析的外部命令
1>
1>生成失败。
1>
1>已用时间 00:00:00.55
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

面试题7:测试时 结构体不吻合

try
{
    BinaryTreeNode* root = Construct(preorder,inorder,length);
    PrintTree(root);

    DestroyTree(root);
}
catch(std::exception& exception)
{
    printf("Invalid Input.\n");
}

其中返回值root的结构类型是BinaryTreeNode:
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};

而下一步传入PrintTree的函数参数类型应该是TreeNode,结构如下:
struct TreeNode
{
int m_nValue;
std::vector<TreeNode*> m_vChildren;
};

二者不吻合导致无法成功测试

面试题第三题代码是不是有问题?

假如前四个数字数字刚刚好,那是不是要把middle换一下?
if(count > (middle - start + 1))
end = middle;
else
start = middle + 1;
应该改为
if(count > (middle - start + 1))
end = middle;
else
start = middle + 1;
middle= end ;

面试题19,复杂度高的可怕

每遇到一个*,就会产生一个分支,,指数级别的复杂度。
用编译原理里面的方法进行优化也好,用动态规划来做也行。如此暴力的解决方式会给人误导的。

面试题18: O(1)删除链表节点 应该加强边界检查

void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted)
{
    if(!pListHead || !pToBeDeleted)
        return;

    // 要删除的结点不是尾结点
    if(pToBeDeleted->m_pNext != nullptr)
    {
        ListNode* pNext = pToBeDeleted->m_pNext;
        pToBeDeleted->m_nValue = pNext->m_nValue;
        pToBeDeleted->m_pNext = pNext->m_pNext;
 
        delete pNext;
        pNext = nullptr;
    }
    // 链表只有一个结点,删除头结点(也是尾结点)
    else if(*pListHead == pToBeDeleted)
    {
        delete pToBeDeleted;
        pToBeDeleted = nullptr;
        *pListHead = nullptr;
    }
    // 链表中有多个结点,删除尾结点
    else
    {
        ListNode* pNode = *pListHead;
        // 加强边界检查,防止意外输入造成core dump
        while(pNode->m_pNext != nullptr && pNode->m_pNext != pToBeDeleted)
        {
            pNode = pNode->m_pNext;            
        }
 
        if (pNode->m_pNext == pToBeDeleted)
        {
            pNode->m_pNext = nullptr;
            delete pToBeDeleted;
            pToBeDeleted = nullptr;
        }
    }
}

面试题16 解法3错误

第三种解法,作者声称的即全面又高效的解法,PowerWithUnsignedExponent(double base, unsigned int exponent),当 exponent < 0时,答案错误

面试题7:重建二叉树

66-67行代码
if(rootInorder == endInorder && *rootInorder != rootValue)
throw std::exception("Invalid input.");
这句没有用吧!

面试题15二进制中1的个数,常规解法代码有误

常规解法中设置一个flag,每次讲flag右移1位并与原来的数字做与运算。书中给的判断条件是 if(n&flag),这个判断是错的。正确的判别式应该是if((n&flag)==flag)。很容易理解,flag从1,2,4,....不断右移,此时按位与得到的结果应该是只有这一位是1,其余全是零,即是flag。作者也帮忙看一下这个想法对嘛

面试题12:函数形参表和内存释放问题

1.第二版书中,面试12的hasPath函数的形参表matrix和str书中为char *,但应该都为const char *应该才能保证字符串数组和矩阵不被修改,并且github中代码是定义成const char *的;
2.存在内存泄漏,在查找通路成功后没有释放visited的内存。

面试题 3 的题目二的说明与实际代码不太符合

该题目已经说明了长度为 n+1 的数组所有数字都在 1~n 范围,那么这个 n 至少应该是 1,否则就没有意义了,所以代码里面有一处判断

if (numbers == nullptr || length <=0)
    return -1;

应该是

if (numbers == nullptr || length <= 1)
    return -1;

剪绳子贪婪算法最优证明没看懂,求解惑!

书中写到:

当n>=5的时候,我们可以证明2(n-2)>n并且3(n-3)>n。也就是说,当绳子剩下的长度大于或者等于5的时候,我们就把它剪成长度为3或长度为2的绳子段

这个“也就是说”结论是怎么得出的?这个结论不是应该证明了3(n-3)>2(n-2)>.....>i(n-i)才能得出吗?

p96-剪绳子-动态规划-products赋值有误

if(length < 2)  return 0;
if(length == 2) return 1;
if(length == 3)  return 2;

。。。。。。。。。。。。。
products[1] = 1;
products[2] = 2;
products[3] = 3;
你上面写的跟下面写的矛盾呀。。。。。

面试题12中的第83到87行代码多余了吧?

按我的理解,这五行代码意思是,此时定位错误,退回到上一个定位。但是,上一个定位处的情况,都已经有递归代码进行检测了,这个回退貌似是多次一举。或者我理解有误,还望指教。

关于拷贝赋值运算符代码的异常安全问题

何老师,这段代码是不是有异常安全问题呀?

CMyString& CMyString::operator = (const CMyString& str)
   {
       if(this == &str)
       return *this;
    
       delete []m_pData;
       m_pData = nullptr;
    
       m_pData = new char[strlen(str.m_pData) + 1];
       strcpy(m_pData, str.m_pData);
    
       return *this;
   }

面试题44

求数字序列中某一位的数字,可以遍历建立哈希表,key为下标,value为数列中对应的值,直接查表就好了啊

面试题3 数组中重复的数字

第二版书中41页提到,"虽然有两个循环,但每个数字最多只要交换两次就能找到属于它自己的位置,所以总时间复杂度是O(n)"

这里不太明白,书中给的例子第一个下标就交换了三次,这个O(n)是怎样得出的呢?

面试题34 错误

page 185 求路径和,返回上一层的时候,currentSum忘记减去pop出的那个节点的值

面试题14:剪绳子 动态规划

我看了一下,代码是没有问题,但我觉得思路有一点问题,书中的代码是这样的
private int maxProductAfterCounter1(int length){
int max=0;
if(length<2)return 0;
if(length==2)return 1;
if(length==3)return 2;
int[] product =new int[length+1];
product[0]=0;
product[1]=1;
product[2]=2;
product[3]=3;
for(int i=1;i<=length;i++){
max=product[i];
for(int j=1;j<=i/2;j++){
int temp=product[j]*product[i-j];
if(temp>max)max=temp;
}
product[i]=max;
}
max=product[length];
return max;
}
这里面没有解释为什么从4开始,为什么长度为4的就必须要剪开,当然我们可以推算出4以后,它每次剪开的乘积都会大于本身,但是没有数学推算,自己写了一个,先假设每一个product最大值是自己本身,由于1,不能剪是自己,2剪了之后没有本身大
private static int maxProductAfterCounter(int length){
int max=0;
if(length<2)return 0;
if(length==2)return 1;
if(length==3)return 2;
int[] product =new int[length+1];
for(int i=1;i<=length;i++)
product[i]=i;
for(int i=1;i<=length;i++){
max=product[i];
for(int j=1;j<=i/2;j++){
int temp=product[j]*product[i-j];
if(temp>max)max=temp;
}
product[i]=max;
}
max=product[length];
return max;
}

面试题14剪绳子,为什么只接收length入参

如题,明明还有剪成m段的要求,但解法中没有考虑到。比如长度为8的绳子,要求剪成2段最大就是4*4=16,要求剪成3段最大就是3*3*2=18,要求剪成4段最大就是2*2*2*2=16。但参考解法中只要输入8输出一定就是18,很疑惑。

41题有疑惑

不应该最小堆应该是从小到大排列,最大堆应该从大到小排列。这样才能保证最小堆的数大于最大堆的数 吗? 为什么原文代码,最小堆从大到小排列,最大堆从小到大排列。谢谢解答

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.