【几数之和系列】四数之和都不会做,面试官让我回去看力扣第一题

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

空间复杂度O(n),最坏的情况下,set存储n个节点的值。

class Solution {

public boolean findTarget(TreeNode root, int k) {

Set set=new HashSet<>();

return find(root,k,set);

}

public boolean find(TreeNode root,int k,Set set){

//如果root为空直接返回false

if(root==null) return false;

if(set.contains(k-root.val)){

return true;

}

//这个没找到就加入到set集合中

set.add(root.val);

//同时去左子树和右子树查找

return find(root.left,k,set)||find(root.right,k,set);

}

}

🐶4.三数之和


给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

题目链接:三数之和

题目分析:这道题和两数之和看上去类似,但做法却不相同,难度也不在一个档次,朴素暴力的做法再最后几个例子会超时

方法1:朴素暴力(超时

时间复杂度O(N^3)

class Solution {

public List<List> threeSum(int[] nums) {

Arrays.sort(nums);

int n=nums.length;

List<List> list=new ArrayList<>();

for(int i=0;i<n-2;i++){

for(int j=n-1;j>i+1;j–){

int x=i+1;

while(x<j){

int count=nums[i]+nums[x]+nums[j];

if(count==0){

List arr=new ArrayList<>();

arr.add(nums[i]);

arr.add(nums[x]);

arr.add(nums[j]);

if(!list.contains(arr)){

list.add(arr);

}

x++;

}else if(count>0){

break;

}else{

x++;

}

}

}

}

return list;

}

}

方法2:排序加双指针

思路:在为了方便去重和减少遍历次数,我们应该保证三指针满足i<j<k的关系。i我们通过for循环固定,j和k从两头向内移动。

时间复杂度O(n2):数组排序O(nlogn),遍历数组O(n),双指针遍历O(n)。总体O(n2)

空间复杂度O(1)

class Solution {

public List<List> threeSum(int[] nums) {

//对数组排序

Arrays.sort(nums);

int n=nums.length;

List<List> list=new ArrayList<>();

for(int i=0;i<n-2;i++){

//定一个i,移动两指针j,k,注意j是从末尾开始移动

int j=i+1;

int k=n-1;

while(j<k){

int count=nums[i]+nums[j]+nums[k];

//找到符合的

if(count==0){

List arr=new ArrayList<>();

arr.add(nums[i]);

arr.add(nums[j]);

arr.add(nums[k]);

//为了去重

if(!list.contains(arr)){

list.add(arr);

}

j++;

k–;

//加起来太大,让k–从而和变小

}else if(count>0){

k–;

//加起来太小,让j++从而和变大

}else{

j++;

}

}

}

return list;

}

}

对上述代码可进行优化:

class Solution {

public List<List> threeSum(int[] nums) {

Arrays.sort(nums);//排序,nums变成递增数组

List<List> res = new ArrayList<>();

//k < nums.length - 2是为了保证后面还能存在两个数字

for(int k = 0; k < nums.length - 2; k++){

if(nums[k] > 0) break;//若nums[k]大于0,则后面的数字也是大于零(排序后是递增的)

if(k > 0 && nums[k] == nums[k - 1]) continue;//nums[k]值重复了,去重

int i = k + 1, j = nums.length - 1;//定义左右指针

while(i < j){

int sum = nums[k] + nums[i] + nums[j];

if(sum < 0){

while(i < j && nums[i] == nums[++i]);//左指针前进并去重

} else if (sum > 0) {

while(i < j && nums[j] == nums[–j]);//右指针后退并去重

} else {

res.add(new ArrayList(Arrays.asList(nums[k], nums[i], nums[j]);

while(i < j && nums[i] == nums[++i]);//左指针前进并去重

while(i < j && nums[j] == nums[–j]);//右指针后退并去重

}

}

}

return res;

}

}

🐯5.四数之和


给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

0 <= a, b, c, d < n

a、b、c 和 d 互不相同

nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

题目链接:四数之和

题目思路:这道题是在三数之和的基础之上个进阶,也可以说是两数之和的进阶,只不过变成了四个数。我们不可能用4个for循环遍历,而且还得去重,肯定是会超时的。这时我们同样可以利用三数之和的性质,先将数组排序,利用四个指针i,p1,p2,j。同时保证i<p1<p2<j。每次固定i和j,判断四个下标相加的和 ,如果比target大,让p2–,如果比target小,让p1++。如果相等就放入到答案集合中。

方法: 排序加双指针

时间复杂度:O(n^3)

空间复杂度:  O(logn)

class Solution {

public List<List> fourSum(int[] nums, int target) {

List<List> list=new ArrayList<>();

Arrays.sort(nums);

int n=nums.length;

//i得保证后面还得有三个位,所以<n-3

for(int i=0;i<n-3;i++){

//得保证和i之间还有两个位,所以>i+2

for(int j=n-1;j>i+2;j–){

int x=nums[i]+nums[j];

//两指针开始的位置

int p1=i+1;

int p2=j-1;

while(p1<p2){

int count=x+nums[p1]+nums[p2];

if(count==target){

List arr=new ArrayList<>();

arr.add(nums[i]);

arr.add(nums[j]);

arr.add(nums[p1]);

arr.add(nums[p2]);

//去重

if(!list.contains(arr)){

list.add(arr);

}

p1++;

p2–;

}else if(count>target){

p2–;

}else{

p1++;

}

}

}

}

return list;

}

}

🐷6.四数相加ll


给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

0 <= i, j, k, l < n

nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

题目链接:四数相加ll

题目思路:这道题其实比上一道题四数之和要简单一些,不过它却也有自己比较难处理的地方。我们不可能用四个for循环遍历,因为即使能遍历不超时,去重的步骤也是很麻烦的。其实也相当于又是两数之和的进阶。我们可以将数组两两分组,A组和B组遍历相加,将结果作为key,value当做该结果出现的次数。然后再遍历C组和D组相加的和为count,去判断map中是否有和count相加为0的key,如果有则加上该key对应的value。这样相当于进行了两次O(n2)的遍历,总体来说还是O(n2)的世界复杂度

方法:分组+哈希表

时间复杂度O(n2):两个两层for循环,总体来时间复杂度还是O(n2)

空间复杂度O(n2):哈希映射需要的空间,最坏的情况下存入的值个数位n2,也就需要O(n^2)的空间

class Solution {

public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {

Map<Integer,Integer> map=new HashMap<>();

int n=nums1.length;

//用来统计答案

int anser=0;

for(int i=0;i<n;i++){

for(int j=0;j<n;j++){

int count=nums1[i]+nums2[j];

//已存在

if(map.containsKey(count)){

//让出现的次数加1,也就是value

map.put(count,map.get(count)+1);

}else{

//未存在,放入map中,value为1

map.put(count,1);

}

}

}

for(int i=0;i<n;i++){

for(int j=0;j<n;j++){

int count2=nums3[i]+nums4[j];

//找到匹配的

if(map.containsKey(-count2)){

//加上value,也就是出现的次数

anser+=map.get(-count2);

}

}

}

return anser;

}

}

总结

对于面试还是要好好准备的,尤其是有些问题还是很容易挖坑的,例如你为什么离开现在的公司(你当然不应该抱怨现在的公司有哪些不好的地方,更多的应该表明自己想要寻找更好的发展机会,自己的一些现实因素,比如对于我而言是现在应聘的公司离自己的家更近,又或者是自己工作到达了迷茫期,想跳出迷茫期等等)

image

Java面试精选题、架构实战文档

整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~

你的支持,我的动力;祝各位前程似锦,offer不断!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

总结

对于面试还是要好好准备的,尤其是有些问题还是很容易挖坑的,例如你为什么离开现在的公司(你当然不应该抱怨现在的公司有哪些不好的地方,更多的应该表明自己想要寻找更好的发展机会,自己的一些现实因素,比如对于我而言是现在应聘的公司离自己的家更近,又或者是自己工作到达了迷茫期,想跳出迷茫期等等)

[外链图片转存中…(img-EpF2hwDq-1713438764653)]

Java面试精选题、架构实战文档

整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~

你的支持,我的动力;祝各位前程似锦,offer不断!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-zFlSOkhb-1713438764654)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值