Leetcode525:连续数组
题目:
方法1:把0变-1,等价于求连续子数组累加和为0的最大连续子数组的长度,但是这种问题都会有一个边界,只要求最大连续子数组的长度都会有边界问题,这个是0,-1 但是如果我改成求累加和为7的最大连续子数组的长度,那么边界就是7,-1,也就是首先把(7,-1)放到map里面
class Solution {
public int findMaxLength(int[] nums) {
//
for(int i=0;i<nums.length;i++){
if(nums[i]==0){
nums[i]=-1;
}
}
//求累加和为0的最大子数组长度
int cur=0;
Map<Integer,Integer> map=new HashMap();
map.put(0,-1);
int max=0;
for(int i=0;i<nums.length;i++){
cur+=nums[i];
if(map.containsKey(cur)){
max=Math.max(max,i-map.get(cur));
}else{
map.put(cur,i);
}
}
return max;
}
}
方法2:就是用一个help数组,记录0和1的数量,每到一个新位置的时候,更新数量,同时计算差值,如果此差值在以前出现过,那么下标相减就是结果,更新max,但是注意一下边界问题,这个问题的边界依然是差值=0,的情况
class Solution {
public int findMaxLength(int[] nums) {
Map<Integer,Integer> map=new HashMap();
int[] help=new int[2];
map.put(0,-1);//同样这个方法也会 有边界问题,也就是如果差值为0,那么从头到尾就是最长
int max=0;
int cha=0;
for(int i=0;i<nums.length;i++){
int a=nums[i]==0?help[0]++:help[1]++;//这个a没用,主要是我想用三木
cha=help[1]-help[0];
if(map.containsKey(cha)){
max=Math.max(max,i-map.get(cha));
}else{
map.put(cha,i);
}
}
return max;
}
}
leetcode 560 和为k连续子数组的数量
题目:
就是计算前缀和,然后看当前前缀和-k是否在以前出现过,map中放的是前缀和以及这个前缀和出现了几次,注意一个边界条件,那就是前缀和为0,默认出现1次,就是到自己算一次。
class Solution {
public int subarraySum(int[] nums, int k) {
Map<Integer,Integer> map=new HashMap();
map.put(0,1);
int res=0;
int cur=0;
for(int i=0;i<nums.length;i++){
cur+=nums[i];
if(map.containsKey(cur-k)){
res+=map.get(cur-k);
}
map.put(cur,map.getOrDefault(cur,0)+1);
}
return res;
}
}
leetcode1074 元素和为目标值的子矩阵数量(我终于自己做出来了,看别人的没看懂。。。菜是原罪)
题目:
分析:就是把矩阵信息压缩,然后变成压缩矩阵求等于k的连续子数组的数量(变成了leetcode560那个题了,我真的太聪明了),矩阵信息压缩太有用了
class Solution {
public int numSubmatrixSumTarget(int[][] arr, int target) {
//同样可以用个压缩矩阵,但是作用和矩阵子序列和最大那个不一样,我这个矩阵表示的是从某一行到此行的总和,然后遍历这个矩阵和target做比较
if(arr==null||arr.length==0||arr[0].length==0){
return 0;
}
int res=0;//非空子矩阵的数量,初始为0
for(int i=0;i<arr.length;i++){
int[] temp=new int[arr[0].length];
for(int j=i;j<arr.length;j++){
Map<Integer,Integer> map=new HashMap();
map.put(0,1);
int cur=0;
for(int k=0;k<arr[0].length;k++){
temp[k]=temp[k]+arr[j][k];
cur+=temp[k];
if(map.containsKey(cur-target)){
res+=map.get(cur-target);
}
map.put(cur,map.getOrDefault(cur,0)+1);
}
}
}
return res;
}
}
leetcode152 乘积最大子序列
题目:
方法1:暴力枚举,超时
class Solution {
public int maxProduct(int[] nums) {
int max=Integer.MIN_VALUE;
for(int i=0;i<nums.length;i++){
for(int j=i;j<nums.length;j++){
int temp=1;
for(int k=j;k<nums.length;k++){
temp*=nums[k];
max=Math.max(max,temp);
}
}
}
return max;
}
}
方法2:换一种思路,就是以i结尾的最大可能,虽然通过了,但是速度贼慢,大概超过了百分之5。。我好奇那百分之5怎么做的。。。
class Solution {
public int maxProduct(int[] nums) {
int max=Integer.MIN_VALUE;
//以i结尾的最大累乘积
for(int i=0;i<nums.length;i++){
int help=1;
int k=i;
while(k>=0){
help=help*nums[k];
max=Math.max(max,help);
k--;
}
}
return max;
}
}
方法3:我开始想的是递归,从最后一位开始,每一步大概需要以前一个节点结束的子序列的最大值,最小值,结果。。。写出来了动态规划???
class Solution {
public int maxProduct(int[] nums) {
int max=Integer.MIN_VALUE;
//换个思路,尝试一下暴力地柜,好改动态规划
int[] help=new int[2];
for(int i=0;i<nums.length;i++){
if(i==0){
help[0]=help[1]=nums[0];
max=Math.max(max,help[0]);
continue;
}
int temp1=help[0];//最大值
int temp2=help[1];//最小值
help[0]=Math.max(nums[i],Math.max(temp1*nums[i],temp2*nums[i]));
help[1]=Math.min(nums[i],Math.min(temp1*nums[i],temp2*nums[i]));
max=Math.max(max,help[0]);
}
return max;
}
}