笔试算法题(06):最大连续子数组和 & 二叉树路径和值
2014-05-16 16:10
369 查看
出题:预先输入一个整型数组,数组中有正数也有负数;数组中连续一个或者多个整数组成一个子数组,每个子数组有一个和;求所有子数组中和的最大值,要求时间复杂度O(n);
分析:
时间复杂度为线性表明只允许一遍扫描,当然如果最终的最大值为0表明所有元素都是负数,可以用线性时间O(N)查找最大的元素。具体算法策略请见代码和注释;
子数组的起始元素肯定是非负数,如果添加的元素为正数则记录最大和值并且继续添加;如果添加的元素为负数,则判断新的和是否大于0,如果小于0则以下一个元素作为起始元素重新开始,如果大于0并且比最大和值小则不更新最大和值,并且继续添加元素;
当然还有分治的解法,将数组分成A和B两个部分,则子数组最大和有三种可能,来自A,来自B和来自A和B的跨界处,时间复杂度为O(NlogN);
如果数组为循环数组,则说明子数组最大和允许出现在array[n-1]和array[0]作为一部分的组合。这样题目分解为两个子题目,一个子题目就是 目标值没有跨过array[n-1]和array[0],其实也就是原来的题目;另一个子题目就是目标值为array[i]到array[n-1]和 array[0]到array[j]的组合,时间复杂度仍旧为O(N);
解题:
出题:输入一个整数和一颗二元树(节点值为整数),从树的根节点开始往下访问每一个节点,直到叶子节点最终形成一条路径。打印出所有节点和与整数值相等路径;
分析:深度优先搜索,使用Stack结构记录路径;
解题:
分析:
时间复杂度为线性表明只允许一遍扫描,当然如果最终的最大值为0表明所有元素都是负数,可以用线性时间O(N)查找最大的元素。具体算法策略请见代码和注释;
子数组的起始元素肯定是非负数,如果添加的元素为正数则记录最大和值并且继续添加;如果添加的元素为负数,则判断新的和是否大于0,如果小于0则以下一个元素作为起始元素重新开始,如果大于0并且比最大和值小则不更新最大和值,并且继续添加元素;
当然还有分治的解法,将数组分成A和B两个部分,则子数组最大和有三种可能,来自A,来自B和来自A和B的跨界处,时间复杂度为O(NlogN);
如果数组为循环数组,则说明子数组最大和允许出现在array[n-1]和array[0]作为一部分的组合。这样题目分解为两个子题目,一个子题目就是 目标值没有跨过array[n-1]和array[0],其实也就是原来的题目;另一个子题目就是目标值为array[i]到array[n-1]和 array[0]到array[j]的组合,时间复杂度仍旧为O(N);
解题:
/** * 子数组累加和必定是从非负数的元素开始 * 如果子数组和小于0则缺省最大值为0 * */ int MaxSubArray(int *array, int count) { int max=0; int curMax=0; for(int i=0;i<count;i++) { curMax+=array[i]; /** * 跳过负数元素,所以目标子数组必定以非负数元素开始 * */ if(curMax < 0) { curMax=0; continue; } /** * 一旦遇到负数元素,除当前负数元素的其他元素的和作为 * 最大值;由于不能保证之后的元素不会让子数组和变得更大 * ,所以累加继续 * */ if(array[i]<0) { if(max<(curMax-array[i])) { max=curMax-array[i]; } } else { if(max<curMax) { max=curMax; } } } return max; } int MaxDif(int *array, int length) { /** * 定义局部stack数组存储相邻元素差值 * 循环获取相邻元素差值 * */ int difarray[length-1]; for(int i=0;i<length-1;i++) { difarray[i]=array[i]-array[i+1]; printf("\n%d",difarray[i]); } /** * sum记录最大和值 * tempsum记录当前元素的和值 * 如果元素为+++++++,则从开始相加到最后 * 如果元素为-------,则sum保持为0 * 如果元素为++++---,则sum保持为前半正数 * 如果元素为----+++,则sum保持为后半正数 * 还有其他满足条件的情况 * */ int tempsum=0, sum=0; for(int i=0;i<length-1;i++) { tempsum+=difarray[i]; if(tempsum<0) tempsum=0; else if(tempsum>sum) sum=tempsum; } return sum; } int main() { int array[]={1,-2,3,10,-4,-7,-2}; printf("the max sub array sum: %d",MaxSubArray(array,7)); return 1; }
出题:输入一个整数和一颗二元树(节点值为整数),从树的根节点开始往下访问每一个节点,直到叶子节点最终形成一条路径。打印出所有节点和与整数值相等路径;
分析:深度优先搜索,使用Stack结构记录路径;
解题:
/** * 使用path记录路径 * */ void SpecialDfs(Node *current, MyStack *path, int sum, int target) { path->push(current->value); sum+=current->value; bool isLeaf=true; if(current->left != NULL) { SpecialDfs(current->left, path, sum, target); isLeaf=false; } if(current->right != NULL) { SpecialDfs(current->right, path, sum, target); isLeaf=false; } if(isLeaf && sum == target) { path->showStack(); } path->pop(NULL); }
相关文章推荐
- 笔试面试算法经典--连续子数组的最大乘积及连续子数组的最大和(Java)
- 笔试算法题(26):顺时针打印矩阵 & 求数组中数对差的最大值
- 算法题15 二叉树的最长的路径长度&&最大路径和
- 算法题15 二叉树的最长的路径长度&amp;&amp;最大路径和
- 编程珠玑读书笔记之----->使用线性算法求解连续子序列的最大和
- 笔试算法题(37):二叉树的层序遍历 & 最长递增的数字串
- 笔试算法题(28):删除乱序链表中的重复项 & 找出已经排好序的两个数组中的相同项
- 算法 | 最大连续子数组
- leetcode:Maximum Subarray(最大的连续子数组) 【面试算法】
- 连续子数组最大和问题(能够处理全是负数,返回子数组的起止索引的O(N)算法)
- 笔试算法题(40):后缀数组 & 后缀树(Suffix Array & Suffix Tree)
- 笔试算法题(31):将有序数组转换成BST表示 & 线段树的应用
- 连续子数组最大和或最大子段和的求解算法及其正确性
- 笔试算法题(07):还原后序遍历数组 & 半翻转英文句段
- 笔试题:求最大连续子数组的最大乘积
- 求连续子数组最大和,两种算法
- 笔试算法题(16):二叉树深度计算 & 字符串全排列
- 【算法拾遗】三种方法求连续子数组的最大和
- 笔试算法题(22):二分法求旋转数组最小值 & 骰子值概率
- [动态规划]最大连续子数组和的四种算法