左右指针
leetcode 15. 三数之和
解题:
- 首先对数组进行排序,排序后固定一个数nums[i],再使用左右指针指向nums[i]后面的两端,数字分别为nums[ L]和nums[R],计算三个数的和sum判断是否满足为0,满足则添加进结果集
- 如果nums[i]大于0,则三数之和必然无法等于0,结束循环
- 如果nums[i]==nums[i-1],则说明该数字重复,会导致结果重复,所以应该跳过
- 当sum==0时,nums[L]==nums[L-1]则会导致结果重复,应该跳过,L++
- 当 sum ==0时,nums[R]==nums[R-1]则会导致结果重复,应该跳过,R–
- 时间复杂度:0(n2),n为数组长度
public List<List<Integer>> threeSum(int[] nums) {
// 排序
Arrays.sort(nums);
ArrayList<List<Integer>> ans = new ArrayList<>();
// 双指针
for (int i = 0; i < nums.length; i++) {
// 满足条件提前结束
if (nums[i]>0) break;
if (i!=0&&nums[i]==nums[i-1]){
continue;
}
int L = i+1;
int R = nums.length-1;
while (L<R){
int sum = nums[i]+nums[L]+nums[R];
if (sum == 0 ){
ans.add(Arrays.asList(new Integer[]{nums[i],nums[L],nums[R]}));
while (L<R && nums[L]==nums[++L]){} //去重
while (L<R && nums[R]==nums[--R]){} //去重
}else if(sum<0){
while (L<R && nums[L]==nums[++L]){}
}else {
while (L<R && nums[R]==nums[--R]){}
}
}
}
return ans;
}
参考:
滑动窗口
76. 最小覆盖子串
滑动窗口框架
public String minWindow(String s, String t){
//目标计数
HashMap<Character, Integer> target = new HashMap<>();
//目标统计
……
//滑动框内计数
HashMap<Character, Integer> window = new HashMap<>();
// 左右指针,左闭右开
int L = 0, R = 0;
while (R < s.length()){
// 移入的元素
Character cr = s.charAt(R);
// 增大窗口
R++;
// 窗口内数据更新
……
// 只要窗口满足条件,就收缩
while(窗口满足条件){
//更新结果
……
// 移出左边的元素
Character cl = s.charAt(L);
//缩小窗口,L++;
L++;
// 窗口内数据更新
……
}
}
return 结果
}
完整代码
public String minWindow(String s, String t){
//目标计数
HashMap<Character, Integer> target = new HashMap<>();
//目标统计
for(Character c:t.toCharArray()){
target.put(c,target.getOrDefault(c,0)+1);
}
//滑动框内计数
HashMap<Character, Integer> window = new HashMap<>();
// 左右指针,左闭右开
int L = 0, R = 0;
// 达成目标个数累计(如果==target.size()表示window框包含所有目标中内容)
int cnt=0;
// 记录最小覆盖子串起始索引、长度
int start = 0,res_len = Integer.MAX_VALUE;
while (R < s.length()){
// 移入的元素
Character cr = s.charAt(R);
// 增大窗口
R++;
// 判断移入的元素是否是target中元素
if(target.containsKey(cr)){
//增加window对应元素数量,注意window中可能没有cr Key,所以用getOrDefault
window.put(cr,window.getOrDefault(cr,0)+1);
// 加入元素可能使窗口接近目标,增加cnt计数
if (window.get(cr).equals(target.get(cr))) cnt++;
}
// 只要窗口满足条件,就收缩
while(cnt == target.size()){
//更新结果
if (R-L <res_len){
start = L;
res_len = R-L;
}
// 移出左边的元素
Character cl = s.charAt(L);
//缩小窗口,L++;
L++;
// 判断移出的元素是否和t中相同
if(target.containsKey(cl)){
// 移出元素可能使窗口不满足条件
if (window.get(cl).equals(target.get(cl))) cnt--;
//减小window对应元素数量
window.put(cl,window.get(cl)-1);
}
}
}
return res_len==Integer.MAX_VALUE?"":s.substring(start,start+res_len);
}
567. 字符串的排列
解答:
public boolean checkInclusion(String s1, String s2) {
HashMap<Character, Integer> target = new HashMap<>();
for (Character c : s1.toCharArray()){
target.put(c,target.getOrDefault(c,0)+1);
}
HashMap<Character, Integer> window = new HashMap<>();
int L=0,R=0;
int cnt = 0;
while (R <s2.length()){
Character cr = s2.charAt(R);
R++;
// 进⾏窗⼝内数据的⼀系列更新
if (target.containsKey(cr)){
window.put(cr,window.getOrDefault(cr,0)+1);
if (window.get(cr).equals(target.get(cr))) cnt++;
}
// 判断左侧窗⼝是否要收缩
while (R - L >=s1.length()){
// 在这⾥判断是否找到了合法的⼦串
if (cnt == target.size()) return true;
Character cl = s2.charAt(L);
L++;
// 进⾏窗⼝内数据的⼀系列更新
if (target.containsKey(cl)){
if (window.get(cl).equals(target.get(cl))) cnt--;
window.put(cl,window.get(cl)-1);
}
}
}
// 未找到符合条件的⼦串
return false;
}
438. 找到字符串中所有字母异位词
解答:
public List<Integer> findAnagrams(String s, String p){
HashMap<Character, Integer> target = new HashMap<>();
for(Character c:p.toCharArray()){
target.put(c,target.getOrDefault(c,0)+1);
}
HashMap<Character, Integer> window = new HashMap<>();
ArrayList<Integer> res = new ArrayList<>();
int L=0,R=0;
int cnt=0;
while (R <s.length()){
Character cr = s.charAt(R);
R++;
if (target.containsKey(cr)){
window.put(cr,window.getOrDefault(cr,0)+1);
if (window.get(cr).equals(target.get(cr))) cnt++;
}
// 判断左侧窗⼝是否要收缩
while (R-L >= p.length() ){
Character cl = s.charAt(L);
if (cnt == target.size()){
res.add(L);
}
L++;
if (target.containsKey(cl)){
if (window.get(cl).equals(target.get(cl))) cnt--;
window.put(cl,window.get(cl)-1);
}
}
}
return res;
}
3. 无重复字符的最长子串
解答
// 滑动窗口 11ms
public int lengthOfLongestSubstring(String s){
HashMap<Character, Integer> map = new HashMap<>();
int L = 0,R = 0 ;
int res = Integer.MIN_VALUE;
while (R < s.length()){
Character cr = s.charAt(R);
R++;
map.put(cr,map.getOrDefault(cr,0)+1);
// 当 map.get(cr) 值⼤于 1 时,说明窗⼝中存在重复字符,不符合条件,就该L++缩⼩窗⼝
while (map.get(cr)>1){
Character cl = s.charAt(L);
L++;
map.put(cl,map.get(cl)-1);
}
// 更新无重复的 最长字串
if (R - L >res ) res = R-L;
}
return res==Integer.MIN_VALUE?0:res;
}