力扣
Posted LinZeLiang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了力扣相关的知识,希望对你有一定的参考价值。
题目
思路1(双指针/滑动窗口)
- 所谓滑动窗口,就是需要我们从一个序列中找到某些连续的子序列,我们可以使用两个for循环来遍历查找,但是未免效率太低了。因此我们可以用一个窗口,从左到右只需要遍历一次,然后每次判断当前窗口是否满足条件,不满足就扩大窗口或者缩小窗口,当滑动窗口从左边滑动到了右边,就可以得到最优解了。
- 滑动窗口的左边界和右边界都只能向右移动,因此只遍历一遍数组,从而时间复杂度是\\(O(N)\\)
- 该题要求是待遍历的序列是从1~target可构建一个滑动窗口从左向右滑动,窗口边界为
left
、right
,初始的时候left=left=1
- 窗口的有效范围就是窗口左边界要小于右边界,即
left < right
- 每次循环中,将窗口里面的数字的总和
sum
与target
进行比较:- 如果
target > sum
,说明窗口大了,需要将当前left
从sum
中删除,同时left
右移一步 - 如果
target < sum
,说明窗口笑了,需要将当前right
从sum
中删除,同时right
右移一步 - 如果
target = sum
,则找到一段序列等于target
,记录下该子序列,同时left
向右移动一步
- 如果
- 我们以
target=9
为例,求解流程如下:
代码
class Solution {
public int[][] findContinuousSequence(int target) {
int sum = 3;
int left = 1;
int right = 2;
List<int[]> res = new ArrayList<>();
while (left < right) {
// 当前窗口符合要求
if (sum == target) {
// 加入到结果集中
int[] temp = new int[right - left + 1];
for (int i = left; i <= right; i++) {
temp[i-left] = i;
}
res.add(temp);
}
// 窗口过大,要缩小窗口
if (sum >= target) {
// 这里要先将left从sum中减去,然后再右移一位,因为当前left是即将被移出窗口,这样才能保证left是窗口的左边界
sum -= left;
left++;
} else if (sum < target) {
// 这里要先将right自增,然后将right加入到sum中,因为先自增才能获取到窗口后一位的元素,然后加入到窗口中,保证了right是窗口的右边界
right++;
sum += right;
}
}
return res.toArray(new int[res.size()][]);
}
}
复杂度分析
- 时间复杂度:\\(O(N)\\),其中
N=target
- 空间复杂度:\\(O(1)\\)
我走得很慢,但我从不后退!
双指针问题复习
文章目录
一般使用的双指针;
- 对撞指针:在一段数据中的开头和结尾,两个指针分别出发;
- 快慢指针:两个指针从左端同时出发; 一个指针移动快,一个指针移动慢;
练习使用
1.力扣[344]反转字符串
编写一个函数,其作用是将输入的字符串反转过来。
输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,
你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
示例 1:
输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入:s = ["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
提示:
1 <= s.length <= 105
s[i] 都是 ASCII 码表中的可打印字符
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution
public void reverseString(char[] s)
//简易对撞指针;
int left =0;
int right =s.length-1;
while(left<right)
//交换两指针对应的字符;
char temp = s[left];
s[left] = s[right];
s[right] = temp;
left ++;
right --;
2.力扣345:反转字符串中的元音字母
原题位置:反转字符串中的元音字母
给你一个字符串 s ,仅反转字符串中的所有元音字母,并返回结果字符串。
元音字母包括 'a'、'e'、'i'、'o'、'u',且可能以大小写两种形式出现。
示例 1:
输入:s = "hello"
输出:"holle"
示例 2:
输入:s = "leetcode"
输出:"leotcede"
提示:
1 <= s.length <= 3 * 105
s 由 可打印的 ASCII 字符组成
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-vowels-of-a-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution
public String reverseVowels(String s)
char[] c = s.toCharArray();
//简易对撞双指针;
int left = 0;
int right = c.length-1;
//仅对元音字母:'a' 'e' 'i' 'o' 'u'反转;
while(true)
//需要验证当前字符是否为元音字母;
while(left < c.length && !isYuanYin(c[left]))
left++;
while(right>=0 && !isYuanYin(c[right]))
right--;
if(left <right)
//交换方法;
swap(c,left,right);
left++;
right--;
else
//若不符,结束当前的循环;
break;
//结束;
return new String(c);
//判断是否为元音字母;
private boolean isYuanYin(char s)
if(s=='a'||s=='e'||s=='i'||s=='o'||s=='u'||
s=='A'||s=='E'||s=='I'||s=='O'||s=='U')
return true;
return false;
//交换两个元素;
private void swap(char[] c,int a,int b)
char temp = c[a];
c[a] = c[b];
c[b] = temp;
3.力扣125:验证回文串
原题位置:验证回文串
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入: "A man, a plan, a canal: Panama"
输出: true
解释:"amanaplanacanalpanama" 是回文串
示例 2:
输入: "race a car"
输出: false
解释:"raceacar" 不是回文串
提示:
1 <= s.length <= 2 * 105
字符串 s 由 ASCII 字符组成
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-palindrome
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
使用对撞双指针解决;
class Solution
public boolean isPalindrome(String s)
int n = s.length();
//特殊用例排除;
if(s==null || n == 0)
return true;
//大写转小写,其他字符忽略;
s = s.toLowerCase();
//对撞指针;
int left = 0;
int right = n-1;
while(left<right)
//使用isLetterOrDigit方法去除非字母和数字的;
while(left<right && !Character.isLetterOrDigit(s.charAt(left)))
left++;
while(left<right && !Character.isLetterOrDigit(s.charAt(right)))
right--;
//若不匹配则直接退出;
if(s.charAt(left)!=s.charAt(right))
return false;
//指针顺利移动;
left++;
right--;
return true;
4.力扣: 两数之和 II - 输入有序数组
原题位置:两数之和 II - 输入有序数组
给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列,
请你从数组中找出满足相加之和等于目标数 target 的两个数。
如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,
则 1 <= index1 < index2 <= numbers.length 。
以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。
你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
你所设计的解决方案必须只使用常量级的额外空间。
示例 1:
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
示例 2:
输入:numbers = [2,3,4], target = 6
输出:[1,3]
解释:2 与 4 之和等于目标数 6 。因此 index1 = 1, index2 = 3 。返回 [1, 3] 。
示例 3:
输入:numbers = [-1,0], target = -1
输出:[1,2]
解释:-1 与 0 之和等于目标数 -1 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
提示:
2 <= numbers.length <= 3 * 104
-1000 <= numbers[i] <= 1000
numbers 按 非递减顺序 排列
-1000 <= target <= 1000
仅存在一个有效答案
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
同样可使用对撞指针解决;
class Solution
public int[] twoSum(int[] numbers, int target)
//使用简易对撞指针;
int left = 0;
int right = numbers.length-1;
while(left<right)
int sum = numbers[left] + numbers[right];
//若相等,则直接输出;
if(sum == target)
return new int[]left+1,right+1;
else if(sum<target)
//若当前和较小;向右移动左指针;
left++;
else
right--;
//若没找到返回-1,-1;
return new int[]-1,-1;
5.力扣[11] 盛水最多的容器问题
原题位置:
给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。
在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。
示例 1:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。
在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1]
输出:1
示例 3:
输入:height = [4,3,2,1,4]
输出:16
示例 4:
输入:height = [1,2,1]
输出:2
提示:
n == height.length
2 <= n <= 105
0 <= height[i] <= 104
同样也是对撞指针解决;
class Solution
public int maxArea(int[] height)
int n = height.length;
//使用双指针;
int left = 0;
int right = n-1;
//结果;
int res =0;
while(left<right)
//木桶短板效应;按照当前区间的最短板计算;
int curWater = (right - left) * Math.min(height[left],height[right]);
//注意此时还要考虑之前的水箱;
res = Math.max(res,curWater);
if(height[left]<height[right])
left ++;
else
right --;
return res;
6.力扣[15] : 三数之和
原题位置:三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,
使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
提示:
0 <= nums.length <= 3000
-105 <= nums[i] <= 105
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution
public List<List<Integer>> threeSum(int[] nums)
List<List<Integer>> list = new ArrayList<>();
int n = nums.length;
//排除特殊特例;
if(n<3)
return list;
//先对数组来次排序;
Arrays.sort(nums);
for(int i =0;i<n;i++)
//假如当前的数已大于0,则直接退出;
if(nums[i]>0)
break;
//对于多次重复的数据,跳过循环;
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)
//此时记录到集合中;
list.add(Arrays.asList(nums[i],nums[left],nums[right]));
//同时也要为左指针和右指针进行减枝;
while(left<right && nums[left]==nums[left+1])
left++;
while(left<right && nums[right]==nums[right-1])
right--;
//注意需要移动指针;
left++;
right--;
//其他两种情况;
else if(sum<0)
//由于数组已经经过排序;若和小,则要向右移动;
left++;
else
right--;
return list;
7.力扣[16] : 接近的三数之和
原题位置:最接近的三数之和
给你一个长度为 n 的整数数组 nums 和 一个目标值 target。
请你从 nums 中选出三个整数,使它们的和与 target 最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。
示例 1:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
示例 2:
输入:nums = [0,0,0], target = 1
输出:0
提示:
3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-104 <= target <= 104
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum-closest
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution
public int threeSumClosest(int[] nums, int target)
//在之前的经典三数之和问题中,需算出三数之和为0的所有组合;
//这里是要三数之和为target目标值;
int n = nums.length;
//数组排序;
Arrays.sort(nums);
//数组的前三个数之和;
int initSum = nums[0]+nums[1]+nums[2];
for(int i=0;i<n;i++)
//同样需要双指针;
int left = i以上是关于力扣的主要内容,如果未能解决你的问题,请参考以下文章