leetcode第15题

简介: 参考了这里-Java-solution)主要思想是,遍历数组,用 0 减去当前的数,作为 sum ,然后再找两个数使得和为 sum。这样看来遍历需要 O(n),再找两个数需要 O(n²)的复杂度,还是需要 O(n³)。巧妙之处在于怎么找另外两个数。最最优美的地方就是,首先将给定的 num 排序。这样我们就可以用两个指针,一个指向头,一个指向尾,去找这两个数字,这样的话,找另外两个数时间复杂度就会从 O(n²),降到 O(n)。而怎么保证不加入重复的 list 呢?要记得我们的 nums 已经有序了,所以只需要找到一组之后,当前指针要移到和当前元素不同的地方。其次在遍

image.png

top15

解法一 暴力解法

无脑搜索,三层循环,遍历所有的情况。但需要注意的是,我们需要把重复的情况去除掉,就是 [1, -1 ,0] 和 [0, -1, 1] 是属于同一种情况的。

publicList<List<Integer>>threeSum(int[] nums) {
List<List<Integer>>res=newArrayList<List<Integer>>();
for (inti=0; i<nums.length; i++) {
for (intj=i+1; j<nums.length; j++)
for (intk=j+1; k<nums.length; k++) {
if (nums[i] +nums[j] +nums[k] ==0) {
List<Integer>temp=newArrayList<Integer>();
temp.add(nums[i]);
temp.add(nums[j]);
temp.add(nums[k]); 
//判断结果中是否已经有 temp 。if (isInList(res, temp)) {
continue;
                    }
res.add(temp);
                }
            }
    }
returnres;
}
publicbooleanisInList(List<List<Integer>>l, List<Integer>a) {
for (inti=0; i<l.size(); i++) {
//判断两个 List 是否相同if (isSame(l.get(i), a)) {
returntrue;
        }
    }
returnfalse;
}
publicbooleanisSame(List<Integer>a, List<Integer>b) {
intcount=0;
Collections.sort(a);
Collections.sort(b);
//排序后判断每个元素是否对应相等for (inti=0; i<a.size(); i++) {
if (a.get(i) !=b.get(i)) {
returnfalse;
        }
    }
returntrue;
}

时间复杂度:n 表示 num 的个数,三个循环 O(n³),而 isInList 也需要 O(n),总共就是 O(n^4)O(n4),leetCode 复杂度到了 O(n^3)O(n3) 一般就报超时错误了,所以算法还得优化。

空间复杂度:最坏情况,即 O(N), N 是指 n 个元素的排列组合个数,即 N=C^3_nN=Cn3,用来保存结果。

解法二

参考了这里-Java-solution)

主要思想是,遍历数组,用 0 减去当前的数,作为 sum ,然后再找两个数使得和为 sum。

这样看来遍历需要 O(n),再找两个数需要 O(n²)的复杂度,还是需要 O(n³)。

巧妙之处在于怎么找另外两个数。

最最优美的地方就是,首先将给定的 num 排序。

这样我们就可以用两个指针,一个指向头,一个指向尾,去找这两个数字,这样的话,找另外两个数时间复杂度就会从 O(n²),降到 O(n)。

而怎么保证不加入重复的 list 呢?

要记得我们的 nums 已经有序了,所以只需要找到一组之后,当前指针要移到和当前元素不同的地方。其次在遍历数组的时候,如果和上个数字相同,也要继续后移。文字表述比较困难,可以先看下代码。

publicList<List<Integer>>threeSum(int[] num) {
Arrays.sort(num); //排序List<List<Integer>>res=newLinkedList<>(); 
for (inti=0; i<num.length-2; i++) {
//为了保证不加入重复的 list,因为是有序的,所以如果和前一个元素相同,只需要继续后移就可以if (i==0|| (i>0&&num[i] !=num[i-1])) {
//两个指针,并且头指针从i + 1开始,防止加入重复的元素intlo=i+1, hi=num.length-1, sum=0-num[i];
while (lo<hi) {
if (num[lo] +num[hi] ==sum) {
res.add(Arrays.asList(num[i], num[lo], num[hi]));
//元素相同要后移,防止加入重复的 listwhile (lo<hi&&num[lo] ==num[lo+1]) lo++;
while (lo<hi&&num[hi] ==num[hi-1]) hi--;
lo++; hi--;
                } elseif (num[lo] +num[hi] <sum) lo++;
elsehi--;
           }
        }
    }
returnres;
}

时间复杂度:O(n²),n 指的是 num

空间复杂度:O(N),最坏情况,即 N 是指 n 个元素的排列组合个数,即 N=C^3_nN=Cn3,用来保存结果。

对于遍历,这里用到了从两头同时遍历,从而降低了时间复杂度,很妙!



相关文章
|
6月前
|
C++ Python
leetcode-283:移动零
leetcode-283:移动零
29 0
|
6月前
|
算法
leetcode:389. 找不同
leetcode:389. 找不同
27 0
|
存储
leetcode:53.最大字序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
49 0
|
机器学习/深度学习
leetcode第50题
求幂次方,用最简单的想法,就是写一个 for 循环累乘。 至于求负幂次方,比如 2^{-10}2−10,可以先求出 2^{10}210,然后取倒数,1/2^{10}1/210 ,就可以了 double mul = 1; if (n > 0) { for (int i = 0; i < n; i++) { mul *= x; } } else { n = -n; for (int i = 0; i < n; i++) { mul *= x; } mul = 1 / mul; }
leetcode第50题
leetcode第46题
这是自己开始想到的一个方法,考虑的思路是,先考虑小问题怎么解决,然后再利用小问题去解决大问题。没错,就是递归的思路。比如说, 如果只有 1 个数字 [ 1 ],那么很简单,直接返回 [ [ 1 ] ] 就 OK 了。 如果加了 1 个数字 2, [ 1 2 ] 该怎么办呢?我们只需要在上边的情况里,在 1 的空隙,也就是左边右边插入 2 就够了。变成 [ [ 2 1 ], [ 1 2 ] ]。
leetcode第46题
leetcode第54题
在 leetcode 的 solution 和 discuss 看了下,基本就是这个思路了,只是实现上有些不同,怎么用来标记是否走过,当前方向,怎么遍历,实现有些不同,但本质上是一样的。就是充分理解题意,然后模仿遍历的过程。
101 0
leetcode第54题
|
算法
leetcode第42题
也就是红色区域中的水, 数组是 height = [ 0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 ] 。 原则是高度小于 2,temp ++,高度大于等于 2,ans = ans + temp,temp = 0。 temp 初始化为 0 ,ans 此时等于 2。 height [ 0 ] 等于 0 < 2,不更新。 height [ 1 ] 等于 1 < 2,不更新。 height [ 2 ] 等于 0 < 2, 不更新。 height [ 3 ] 等于 2 >= 2, 开始更新 height [ 4 ] 等于 1 < 2,temp = temp + 1 = 1。 h
100 0
leetcode第42题
|
存储 算法 Java
leetcode第29题
这道题看起来简单,却藏了不少坑。首先,我们用一次一次减造成了超时,然后我们用递归实现了加倍加倍的减,接着由于 int 表示的数的范围不是对称的,最小的负数并不能转换为对应的相反数,所以我们将之前的算法思路完全逆过来,正数边负数,大于变小于,还是蛮有意思的。
leetcode第29题
leetcode第25题
时间复杂度:while 循环中本质上我们只是将每个结点访问了一次,加上结点倒置访问的一次,所以总共加起来每个结点其实只访问了 2 次。所以时间复杂度是 O(n)。 空间复杂度:O(1)。 解法二递归 有没有被解法一的各种指针绕晕呢,我们有一个更好的选择,递归,这样看起来就会简洁很多。 public ListNode reverseKGroup(ListNode head, int k) { if (head == null) return null; ListNode point = head; //找到子链表的尾部 int i = k;
leetcode第25题
leetcode第12题
相当简洁了,主要就是把所有的组合列出来,因为罗马数字表示的大小就是把所有字母相加,所以每次 append 那个,再把对应的值减去就行了。 时间复杂度:不是很清楚,也许是 O(1)?因为似乎和问题规模没什么关系了。 空间复杂度:O(1)
leetcode第12题