刷题记录|目标101题--双指针
写在前面
开个贴记录一下刷题的过程,目前参照leetcode101,目标101题,由于太久没写java了,也会涉及到一些java的基础用法,希望能和大家共勉吧~
已刷链接:
双指针
No.1 Two Sum II - Input Array Is Sorted
题目链接:https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/
设计到的算法:双指针
解题思路:左右各一个指针滑动既可
class Solution {
public int[] twoSum(int[] numbers, int target) {
int i = 0, j = numbers.length - 1;
while(numbers[i] + numbers[j] != target) {
if (numbers[i] + numbers[j] < target) {
i ++;
} else {
j --;
}
}
int[] result = {++i,++j};
return result;
}
} No.2 Merge Sorted Array
题目链接:https://leetcode.com/problems/merge-sorted-array/
涉及到的算法:双指针
解题思路:
从前往后的两个指针不可行因为会覆盖,那么考虑从后往前数两个指针,发现从后往前是work的
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m - 1, j = n - 1, current = m + n - 1;
while (i >= 0 && j >= 0) {
if (nums1[i] > nums2[j]) {
nums1[current--] = nums1[i--];
} else {
nums1[current--] = nums2[j--];
}
}
while(i >= 0) {
nums1[current--] = nums1[i--];
}
while(j >= 0) {
nums1[current--] = nums2[j--];
}
}
} No. 3 Linked List Cycle II
题目链接:https://leetcode.com/problems/linked-list-cycle-ii/
涉及到的算法:快慢指针
解题思路:快慢指针
快慢指针中如果用图表示就是将路径分为abc三段,a表示从链表头到成环点,b表示从环点到相遇处,c表示从相遇处到环点,其计算公式如下(图好丑TT)
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null) return null;
ListNode fast = head;
ListNode slow = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
break;
}
}
if (fast.next == null || fast.next.next == null) {
return null;
}
fast = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
} No.4 Minimum Window Substring
题目链接:https://leetcode.com/problems/minimum-window-substring/ 涉及到的算法:滑动窗口
解题思路:
首先需要先遍历一遍string t,用数组记录下来他的character出现的次数。
用l和r指针遍历这个数组,在遍历时及时更新这个数组。
- 如果r滑过了则将对应character次数--,
- 如果l滑过了,此时如果只是单一的character数组,我们在看到l指针指向的字符对应在character数组中的计数为0时,无法区分是这个字符从未在string t中出现过,可以划走还是出现过但是正好被指针r覆盖,所以展示的0,此时不能划走,故引入数组flag[],在首次遍历时同时记录数组character和数组flag
- 需要将string s从头到位遍历一遍,存储一个最小值,中间每次满足条件时将值与最小值对比,如果比最小值还要小更新最小值
- 涉及到的java原理:
class Solution {
public String minWindow(String s, String t) {
if (t.length() > s.length()) return "";
int[] characters = new int[128];
boolean[] flag = new boolean[128];
for (int i = 0; i < t.length(); i++) {
int index = t.charAt(i);
flag[index] = true;
characters[index]++;
}
int begin_index = 0, end_index = s.length(),count = 0;
for (int r = 0,l = 0; r < s.length(); r++) {
int indexR = s.charAt(r);
if (flag[indexR] && characters[indexR]-- > 0) {
count++;
}
while (count == t.length()) {
int indexL = s.charAt(l);
if (flag[indexL] && ++characters[indexL] > 0) {
if (r-l+1 < end_index-begin_index +1) {
begin_index = l;
end_index = r;
}
count--;
}
l++;
}
}
return end_index == s.length() ? "" : s.substring(begin_index,end_index+1);
}
} No.5 Sum of Square Numbers
题目链接:https://leetcode.com/problems/sum-of-square-numbers/
涉及到的算法:双指针
解题思路:
Two Sum 变种
这里需要注意两点:
- 不能将r=c/2,而要使用java的开根号方法double Math.sqrt(),向下取整,防止溢出
- 因为 0 <= c && c <= 231 - 1,我们在计算时如果使用 a2 + b2 容易溢出,可以使用 c - a2 的形式去判断,就不会溢出了
class Solution {
public boolean judgeSquareSum(int c) {
if (c <= 2) return true;
int l = 0, r = (int)(Math.sqrt(c));
while(l <= r) {
int left = l * l;
int right = c - left;
if (right == r * r) {
return true;
} else if (right < r * r) {
r --;
} else {
l ++;
}
}
return false;
}
} No.6 Valid Palindrome II
题目链接:https://leetcode.com/problems/valid-palindrome-ii/
涉及到的算法:双指针
解题思路:左右各一个指针,遇见不同时尝试跳过左边的数字和跳过右边的数字两种情况就可以。
class Solution {
public boolean validPalindrome(String s) {
int l = 0, r = s.length() - 1;
while (l < r && s.charAt(l) == s.charAt(r)) {
l++;r--;
}
if (s.charAt(l) == s.charAt(r)) return true;
return isPalindrome(s.substring(l + 1,r + 1)) || isPalindrome(s.substring(l,r));
}
private boolean isPalindrome(String s) {
int l = 0, r = s.length() - 1;
while (l < r && s.charAt(l) == s.charAt(r)) {
l++;r--;
}
if (s.charAt(l) == s.charAt(r)) return true;
return false;
}
} No.7 Longest Word in Dictionary through Deleting
题目链接:https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/ 涉及到的算法:双指针
解题思路:
先给 dictionary 排序,排完以后就是一个简单的对比string的问题
class Solution {
public String findLongestWord(String s, List<String> dictionary) {
Collections.sort(dictionary,(a,b) -> {
if (a.length() != b.length()) {
return b.length() - a.length();
}
for (int i = 0; i < a.length(); i++) {
if (a.charAt(i) != b.charAt(i)) {
return a.charAt(i) - b.charAt(i);
}
}
return 0;
});
for(int i = 0; i < dictionary.size();i++) {
if (dictionary.get(i).length() > s.length()) {
continue;
}
String target = dictionary.get(i);
int j = 0,k = 0;
for(; j < s.length() && k < target.length(); j++) {
if (s.charAt(j) == target.charAt(k)) {
k++;
}
}
if (k == target.length()) {
return target;
}
}
return "";
}
} No. 8 Longest Substring with At Most K Distinct Characters
本题需要leetcode会员,贫穷的我选择直接看好心人的题解T T:https://aaronice.gitbook.io/lintcode/two_pointers/longest_substring_with_at_most_k_distinct_characters
涉及到的java知识:
题目:
解题思路:
求一个最长的substring的length,可以知道我们的思路是采用一个双指针的滑动窗口,在滑动的过程中去更新这个length,生息的问题是如何去维护这个滑动窗口。
我们要能确定这个这个substring的窗口中有几种字符需要额外开辟一块存储空间,去存储在这个窗口中哪些字符出现了,出现了几次。
我们需要获取在这个窗口中出现的distinct character的数量,但是数组无法确定究竟有哪些不同的character被存入,所以我们要换用可以直接获得size的hashmap进行储存,开辟一块存储,存储对应character出现次数的index
如何滑动:
设置一个左指针firstIndex 一个右指针endInex表示滑动窗口的起始与结尾,每次将endInex右++,将其指向的character存入hashMap,如果曾经有就将其次数++;
如果此时hashMap的size已经大于k了,就可以开始移动左指针firstIndex,进行删除操作,直到size不再大于k;
每次移动右指针时更新最长的值,最后返回记录的最长的值
#力扣刷题##逃离互联网#
查看16道真题和解析
阿里巴巴公司氛围 652人发布
