算法总结
算法总结
1.二分查找
2.移除元素
1.移除元素
思路:
快慢指针,left 更新数组,right 向右走
代码:
class Solution {
public int removeElement(int[] nums, int val) {
int n=nums.length;
int left=0,right=0;
for(;right<n;right++){
if(nums[right]!=val){
nums[left]=nums[right];
left++;
}
}
return left;
}
}
3.滑动窗口
1.水果成篮
思路:
left right指向两个水果,不断更新
代码:
class Solution {
public int totalFruit(int[] fruits) {
int n=fruits.length;
int left=0,right=1;
if(n==1) return 1;
int ln=fruits[left],rn=fruits[right];
int ans=0;
while(right<n){
if(fruits[right]==ln||fruits[right]==rn){
ans=Math.max(ans,right-left+1);
right++;
}
else{
left=right-1;
ln=fruits[left];
while(left>=1&&fruits[left-1]==ln) left--;
rn=fruits[right];
ans=Math.max(ans,right-left+1);
}
}
return ans;
}
}
链表
1.双指针
1.环形链表||
题目链接:142. 环形链表 II - 力扣(LeetCode)
思路:
双指针,fast一次走两次, slow 一次走一次,然后他们肯定会在环形链表内交上,然后 x=(n-1)(y+z)+z, 当n=1时,x=z,从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点,当n!=1时,相遇节点也是多走了(n-1)圈,然后与头结点相遇
代码:
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null){
slow=slow.next;
fast=fast.next.next;
if(slow==fast){
ListNode index1=fast;
ListNode index2=head;
while(index1!=index2){
index1=index1.next;
index2=index2.next;
}
return index1;
}
}
return null;
}
}
2.删除链表的倒数第N个节点
题目链接:19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
思路:
首先设一个虚拟头结点,删除倒数第N个节点就是找到前一个节点为第M-N个节点,然后fast指针先走N步,slow指针在原地,然后两指针一起走,直到fast.next指针为空,即走了M-N步,slow指针指向第M-N个节点,然后 slow.next=slow.next.next;
代码:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode p=head;
ListNode q = new ListNode(0, head);
ListNode fast=q;
ListNode slow=q;
while(n-->0&&fast!=null){
fast=fast.next;
}
while(fast.next!=null){
fast=fast.next;
slow=slow.next;
}
slow.next=slow.next.next;
return q.next;
}
}
字符串:
1.双指针法
反转字符串经常用到
2.反转系列
在反转上还可以在加一些玩法,其实考察的是对代码的掌控能力。双指针法用的比较多
3.KMP
KMP的主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了.
KMP的精髓所在就是前缀表
前缀表:起始位置到下标i之前(包括i)的子串中,有多大长度的相同前缀后缀。
题目:
KMP思想
代码:
class Solution {
public int strStr(String haystack, String needle) {
if (needle.length() == 0) return 0;
int[] next = new int[needle.length()];
getNext(next, needle);
int j = 0;
for (int i = 0; i < haystack.length(); i++) {
while (j > 0 && needle.charAt(j) != haystack.charAt(i))
j = next[j - 1];
if (needle.charAt(j) == haystack.charAt(i))
j++;
if (j == needle.length())
return i - needle.length() + 1;
}
return -1;
}
private void getNext(int[] next, String s) {
int j = 0;//前缀末尾位置
next[0] = 0;
// i 是后缀末尾位置
for (int i = 1; i < s.length(); i++) {
// i 和 j 位置字母不相等
while (j > 0 && s.charAt(j) != s.charAt(i))
j = next[j - 1];
// i 和 j 位置字母相等
if (s.charAt(j) == s.charAt(i))
j++;
next[i] = j;
}
}
}
思路:
KMP,
假设字符串s使用多个重复子串构成(这个子串是最小重复单位),重复出现的子字符串长度是x,所以s是由n * x组成。
因为字符串s的最长相同前后缀的长度一定是不包含s本身,所以 最长相同前后缀长度必然是m * x,而且 n - m = 1,(这里如果不懂,看上面的推理)
所以如果 nx % (n - m)x = 0,就可以判定有重复出现的子字符串。
代码:
class Solution {
public boolean repeatedSubstringPattern(String s) {
int[] next = getNext(s);
// 长度 % (长度 - 最长前后缀) == 0
if (next[s.length() - 1] != 0 && s.length() % (s.length() - next[s.length() - 1]) == 0) {
return true;
}
return false;
}
public int[] getNext(String str) {
int[] next = new int[str.length()];
next[0] = 0;
int j = 0;
for (int i = 1; i < str.length(); i++) {
// 找到最长相等前后缀长度
while (j > 0 && str.charAt(i) != str.charAt(j)) {
j = next[j - 1];
}
// 如果匹配, 长度则再加1
if (str.charAt(i) == str.charAt(j)) {
j++;
}
next[i] = j;
}
return next;
}
}
双指针
1.n数之和
通解:排序+双指针
代码:
class Solution {
public List<List<Integer>> fourSum(int[] nums, int tar) {
// n数之和通用解法,排序+固定枚举前n-2个数字,双指针搜索最后两个数字。
// 每个数字向后搜索时直接去重。
int n = nums.length;
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<List<Integer>>();
if(n < 4)
return ans;
for(int i = 0; i < n-3; ++i){
if(i > 0 && nums[i] == nums[i-1])
continue;
for(int j = i+1; j < n-2; ++j){
if(j > i + 1 && nums[j] == nums[j-1])
continue;
int l = j + 1, r = n-1;
while(l < r){
long sum = (long)nums[i] + nums[j] + nums[l] + nums[r];
if(sum == (long)tar){
ans.add(Arrays.asList(nums[i],nums[j],nums[l++],nums[r--]));
while(l < r && nums[l] == nums[l-1])
++l;
while(l < r && nums[r] == nums[r+1])
--r;
}else if(sum < (long)tar){
++l;
}else{
--r;
}
}
}
}
return ans;
}
}

浙公网安备 33010602011771号