今天终于开始刷力扣了,一刷就是两数到四数,这谁能料得到呢?菜鸡刷题都是:视频题解+讨论区题解=自己的题解。刚刚开封,有点小小の成就感~其中大部分是Java过的
话不多说,进入正篇,从两数之和开始吧!
两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
这题无脑暴力的话,很好做,但是复杂度为O(n^2),不太行的🦆!还记得我们昨天说的宗旨吗!哦不,应该是前天了~管他呢,这个宗旨无论何时都不会变——不妨时间换空间!这题通常的空间是用的map,由于需要返回的是数组下标,所以我们把数值作为键,下标作为值(通过值去找下标)
思路很巧妙,遍历到一个元素时,如果发现target-这个元素的值在map里的话,就把这两者的下标放入一个只有俩元素的数组返回,否则,如果不在map里的话,就把遍历得到的这个元素的值和下标加入map(这是为了在后面如果遇到了它的真命天子就可以一起快乐回城啦!)
代码时间
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] res = new int[2];
if(nums.length <= 1) return res;
HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
for(int i = 0; i < nums.length; i++){
int num = nums[i];
int value = target - num;
if(map.containsKey(value)){
res[0] = i;
res[1] = map.get(value);
return res;
}else {
map.put(num,i);
}
}
return res;
}
}
三数之和
三数、四数就没法再利用一个数据结构去开辟空间了,需要我们自己老老实实地遍历,当然也不会非常老实地写个三重循环(见过。。找n个还真的写n重循环的,这就是后浪吗??tql(/≧▽≦)/)首先,排序;然后,适当剪枝(四数里剪枝的优势更明显);最后,返回。
其实根本思路是第一个数遍历,后面两个数弄个区间去加加减减,四数里就是再套一层遍历。
注意:要跳过相同元素
这里第一个元素的“跳”和后面区间边界的“跳”不太一样——第一个元素要跳的话,要拿自己和前一个比(从第二个元素开始);区间元素如果要跳的话,(以左边界为例)拿自己和后一个比,如果相等就跳,跳完之后还有是要++
因为如果第一个元素和后一个元素相等就continue的话,会漏解,比如[-1,-1,2],虽然第一个元素不能再是-1了,但是第二个元素还可以是-1。
区间挪移类似二分。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList();
if(nums.length <= 2) return res;
int n = nums.length;
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
if(nums[i]>0) break; //如果第一个就>0,就没有必要了
if(i>0&&nums[i]==nums[i-1]) continue; //去重
int left = i+1;
int right = n-1;
while(left < right){
int sum = nums[i] + nums[left] + nums[right];
if(sum==0){
res.add(Arrays.asList(nums[i],nums[left],nums[right]));//巧妙!一行解决
while(left<right && nums[left+1]==nums[left]) left++;
while(left<right && nums[right-1]==nums[right]) right--;
left++;
right--;
}else if(sum<0) left++;
else right--;
}
}
return res;
}
}
四数之和
既然已经排好了序,就要好好利用这个顺序的优势——如果前面(最小的四个都>target了)就直接break好了,后面就不用看了,肯定更大;如果本元素加上最后面三个<target了,本轮也不用继续了,直接continue吧。
除了多套了一层循环,多了一些剪枝的操作,其他基本与上题无异。
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
if(nums.length <= 3) return res;
Arrays.sort(nums);
int length = nums.length;
//k从0开始,i从k+1开始,j指向i+1,h指向最大值(最后一个元素)
for(int k = 0; k < length-3; k++){
if(k>0 && nums[k]==nums[k-1]) continue;//去重
if((nums[k]+nums[k+1]+nums[k+2]+nums[k+3])>target) break;//不用看了
if((nums[k]+nums[length-1]+nums[length-2]+nums[length-3])<target) continue;
for(int i = k+1; i < length-2; i++){
if(i>k+1 && nums[i]==nums[i-1]) continue;
int j = i+1;
int h = length-1;
if((nums[k]+nums[i]+nums[j]+nums[j+1])>target) break;
if((nums[k]+nums[i]+nums[h]+nums[h-1])<target) continue;
while(j < h){
int curr = nums[k]+nums[i]+nums[j]+nums[h];
if(curr == target){
res.add(Arrays.asList(nums[k],nums[i],nums[j],nums[h]));
while(j<h && nums[j]==nums[j+1]) j++;
while(j<h && nums[h]==nums[h-1]) h--;
j++;
h--;
}else if(curr < target) j++;
else h--;
}
}
}
return res;
}
}
今天打卡完成!晚上争取把“流”的博文写完!英语考试冲冲冲!tnnd马原居然用学习通手机端人脸识别监考,呜呜呜呜,展现我超凡 炒饭记忆力的时候又到了!加油!你相信自己可以你就可以!你看的《鬼灭》还有《刀剑》都极力在渲染一件事——信念的力量!现在我说起来多少有些苍白,自己去看,用心感受你就会察觉到笔者用心用力去传达的东西~