第一题
给定一个数组arr 求子数组最大累加和
最暴力的 枚举每一个子数组 出结果
优化解 用一个cur指针保存累加和 每次cur变大 就用它更新max 如果cur累加到0以下 回复成0
假设答案法 假设我们最大的子数组是i 到 j位置上的
那么这个i 到j 之间 必不存在一个k使i...k累加和小于0 因为如果小于0了 那这个子数组就不是最大的
而且这个 i-1....k不可能大于0 如果大于0了 那为什么不把i-1算进来 让这个子数组变得更大?
所以这个cur是什么含义 我们使用cur在累加数组 也就是说 当cur回滚成0的时候 就是新的子数组的开始
当cur累加到0以下 就说明 我们已经走到一个k...i累加和小于0的部分了 这部分肯定不是答案
(如果下一个数字还是负数 那cur还是0 也就是说这个点也不要)
或者我们用自然思维想一下 这个cur累加<0 就说明前面这一部分已经是<0了 我们加上它只会让累加和变小 那就要舍弃掉 你是不是在想 那当这个 减小的区间 前面有一个大的区间 那我们岂不是把这个更大的区间舍弃掉了 并不会 我们的cur会先累加大区间 然后再去加小区间 如果这个大区间还没有被小区间抵消的话 就不会被舍弃掉
public int maxSubArray(int[] nums) {
int cur = 0;
int max = Integer.MIN_VALUE;
for (int i : nums) {
cur += i;
max = Math.max(cur, max);
cur = cur<0?0:cur;
}
return max;
}
当<0的时候 它调整为0这一步 不加入max的计算 假如说nums 只有-1 吧 你调整回0去了 再比 那最大累加和就是0了
还有我刚开始写成这样了
那总要跳过 不如直接把它放在最后一步 是一样的 还不会跳过max的比较操作(面对-1用例的时候不行)
第二题
给定一个正整数、负整数和 0 组成的 N × M 矩阵,编写代码找出元素总和最大的子矩阵。
返回一个数组 [r1, c1, r2, c2]
,其中 r1
, c1
分别代表子矩阵左上角的行号和列号,r2
, c2
分别代表右下角的行号和列号。若有多个满足条件的子矩阵,返回任意一个均可。
给一个矩阵
5 -3 2 7
-6 3 2 -1
7 2 -5 4
矩阵有一个什么特点呢 如果我想要5 -3和 7 2 的话 那中间的-6 3 2 -1也得要 这个耦合性很强 我们可以用这个特点优化
先遍历每一个满长方形 就是每一行全要 比如
5 -3 2 7
-6 3 2 -1
7 2 -5 4
这三个长方形是 高度为1的
5 -3 2 7
-6 3 2 -1
-6 3 2 -1
7 2 -5 4
这两个是高度为2的
5 -3 2 7
-6 3 2 -1
7 2 -5 4
这个是高度为3的
由于矩阵的耦合性 要一行必须要其他的行 我们可以直接把它压缩成一行 然后在这个行上面找 最大子数组累加和
lass RES{
int max;
int [] row = new int [2];
int [] col = new int [2];
}
class Solution {
public int[] getMaxMatrix(int[][] matrix) {
int [] sum = null;
int max = Integer.MIN_VALUE;
RES maxres = new RES();
maxres.max = Integer.MIN_VALUE;
for(int i = 0;i<matrix.length;i++) {
sum = new int [matrix[0].length];
for(int j = i;j<matrix.length;j++) {
for(int t = 0;t<matrix[0].length;t++) {
sum[t]+=matrix[j][t];
}
RES res = getMax(sum);
res.col = new int [] {i,j};
if(res.max>maxres.max) {
maxres = res;
}
}
}
return new int [] {maxres.col[0],maxres.row[0],maxres.col[1],maxres.row[1]};
}
public RES getMax(int [] arr) {
int cur = 0;
int max = Integer.MIN_VALUE;
int size = 0;
int fin = 0;
int maxsize = 0;
for (int i = 0;i<arr.length;i++) {
cur+=arr[i];
size++;
if(cur>max) {
max = cur;
fin = i;
maxsize = size;
}
if(cur<0) {
cur = 0;
size = 0;
}
}
RES res = new RES();
res.max = max;
res.row = new int [] {fin-maxsize+1,fin};
return res;
}
}
累死我了
题目三
求完全二叉树节点的个数要求时间复杂度低于O(N)
每层都是满的 如果最后一层不满 那也是从左往右变满的
找到他最左边的那条边 直接扎到底
看它有多少层
然后再找 右树的最左节点 如果和刚才的层数相同 那就说明左树全满
那下一步就是查右树的节点数
那要是没有左树高呢 那就说明右树 是满的 但是比左树的 高度 要矮一层
递归查左树的节点数
public int countNodes(TreeNode root) {
return Process(root);
}
public int Process(TreeNode root) {
if(root==null) {
return 0;
}
TreeNode leftcur = root;
int left = 1;
int right = 1;
while(leftcur.left!=null) {
leftcur = leftcur.left;
left++;
}
if(root.right!=null) {
right++;
}
TreeNode rightcur = root.right;
while(rightcur!=null&&rightcur.left!=null) {
rightcur = rightcur.left;
right++;
}
if(right==left) {
return (int) (Math.pow(2, left-1)+Process(root.right));
}else {
return (int) (Math.pow(2, right-1)+Process(root.left));
}
}
(rightcur!=null&&rightcur.left!=null)
hhh 虽然这里记得null.right会报错 但是搞反了