1、最长无重复子数组--返回数组长度

public int maxLength (int[] arr)

【算法题型总结】--3、双指针_i++

解法1:set

import java.util.*;

public class Solution {
/**
*
* @param arr int整型一维数组 the array
* @return int整型
*/
public int maxLength (int[] arr) {
// write code here
int n = arr.length;
int start = 0, end = 0;
int max = 0;

while (start <= end && end < n) {
Set set = new HashSet<>();
while (end < n && set.add(arr[end])) {
if (end == n - 1) break;
end++;
}
max = Math.max(max, set.size());
if (end == n - 1) break;
start = end;
}
return max;
}
}

解法2:滑动窗口(双指针)

经典滑动窗口
import java.util.*;

public class Solution {
/**
*
* @param arr int整型一维数组 the array
* @return int整型
*/
public int maxLength (int[] arr) {
// write code here
// 滑动窗口
if (arr == null || arr.length == 0) return 0;
HashMap window = new HashMap<>();
int left = 0, right = 0;
int n = arr.length;
int res = -1;
while (right < n) {
int in = arr[right];
right++;
window.put(in, window.getOrDefault(in, 0)+1);
while (window.get(in) > 1) {
int out = arr[left];
left++;
window.put(out, window.getOrDefault(out, 0)-1);
}
res = Math.max(res, right - left);
}
return res;
}
}

5、合并两个有序的数组  NC22

public void merge(int A[], int m, int B[], int n)

【算法题型总结】--3、双指针_i++_02

 解法1:从后往前比较&使用函数

public class Solution {
public void merge(int A[], int m, int B[], int n) {
int i=m, j=n;
while(m>0 && n>0){
if(A[m-1] >= B[n-1]){
A[m+n-1] = A[m-1];
m--;
}else{
A[m+n-1] = B[n-1];
n--;
}
}
if(m==0) System.arraycopy(B, 0, A, 0, n);
}
}

public class Solution {
public void merge(int A[], int m, int B[], int n) {
int p1 = m - 1;
int p2 = n - 1;
int index = m + n - 1;
while (p1 >= 0 && p2 >= 0) {
A[index--] = A[p1] > B[p2] ? A[p1--] : B[p2--];
}
while (p2 >= 0) {
A[index--] = B[p2--];
}
}
}

 6、删除链表的倒数第n个节点

public ListNode removeNthFromEnd (ListNode head, int n)

【算法题型总结】--3、双指针_java_03

 

 方案:先走n步,然后快慢一起走,直到最后

public String solve (String str)

public class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode first = head;
ListNode second = head;
for(int i = 0; i < n; i++)
first = first.next;
//如果n的值等于链表的长度,直接返回去掉头结点的链表
if(first == null)
return head.next;
while(first.next != null) //同时移动两个指针
{
first = first.next;
second = second.next;
}
second.next = second.next.next;
return head;
}
}

7、反转字符串

public String solve (String str)

import java.util.*;

public class Solution {
public static void main(String[] args){
Solution s = new Solution();
String str = "abcd";
String str1 = s.solve(str);
System.out.println(str1);
}
//思路:将字符串里的字符对称相互替换
// 将字符串转为字符数组
public String solve (String str) {
char[] ch = str.toCharArray();
for(int i = 0;i < ch.length/2;i++){
char temp = ch[i];
ch[i] = ch[ch.length-1-i];
ch[ch.length-1-i] = temp;
}
String s = new String(ch);
return s;
}
}

或StringBuilder对象的reverse方法

8、NC54 数组中相加和为0的三元组

public ArrayList<ArrayList<Integer>> threeSum(int[] num)

【算法题型总结】--3、双指针_滑动窗口_04

 

 i循环,left和right从i右侧开始移动,判断三数之和并进行移动

import java.util.*;
public class Solution {
public ArrayList> threeSum(int[] num) {
//双指针
Arrays.sort(num);//排序
ArrayList> ans=new ArrayList>();
for(int i=0;i {
int left=i+1;
int right=num.length-1;
if(i>0&&num[i]==num[i-1])continue;//若相同,则跳过
while(left {
if(num[i]+num[left]+num[right]==0)
{ //三数相加为0,则输出
ArrayList list=new ArrayList<>();
list.add(num[i]);
list.add(num[left]);
list.add(num[right]);
left++;right--;
ans.add(list);
//若相同,则跳过
while(left while(left }
if(num[i]+num[left]+num[right]<0)left++;//三数相加小于0,left右移
if(num[i]+num[left]+num[right]>0)right--;//三数和大于0,right左移
}
}
return ans;
}
}

9、NC128 接雨水问题

给定一个整形数组arr,已知其中所有的值都是非负的,将这个数组看作一个柱子高度图,计算按此排列的柱子,下雨之后能接多少雨水。

【算法题型总结】--3、双指针_i++_05

public long maxWater (int[] arr)

【算法题型总结】--3、双指针_滑动窗口_06

 

 方案:左右双指针找最大的作为对应的数组值,遍历原数组,结果为左右低的减去当前

public long maxWater (int[] arr) {
// write code here
if(arr.length <= 2){
return 0;
}
int[] left = new int[arr.length];
left[0] = 0;
int leftMax = arr[0];
for(int i = 1 ; i < arr.length; i++){
leftMax = Math.max(leftMax,arr[i-1]);
left[i] = leftMax;
}
int[]right = new int[arr.length];
right[arr.length-1] = 0;
int rightMax = arr[arr.length-1];
for(int j = arr.length -2;j>=0;j--){
rightMax = Math.max(rightMax,arr[j+1]);
right[j] = rightMax;
}
long result = 0;
for(int k = 1; k < arr.length-1;k++){
result += Math.max(Math.min(left[k],right[k]) - arr[k],0);
}
return result;
}

10、NC96 判断一个链表是否为回文结构

public boolean isPail (ListNode head)

【算法题型总结】--3、双指针_滑动窗口_07

 

 方法1:反转后比较

import java.util.*;

public class Solution {

public boolean isPail (ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode reverseList = reverse(slow);
ListNode cur1 = reverseList, cur2 = head;
while (cur1 != null) {
if (cur1.val != cur2.val) {
return false;
}
cur1 = cur1.next;
cur2 = cur2.next;
}
return true;
}

public ListNode reverse(ListNode head) {
ListNode cur = head, pre = null;
while (cur != null) {
ListNode tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
}

方法2:入栈再出栈比较

方法3:存入数组,判断是否相等

public boolean isPail (ListNode head) {
// write code here
ArrayList arr=new ArrayList<>();
while (head!=null){
arr.add(head.val);
head=head.next;
}
for (int i=0;i //注意,此处最初写的是arr.get(i)!=arr.get(arr.size()-i-1),但是一直有测试例子无法通过
//还是equal牛逼
if (!arr.get(i).equals(arr.get(arr.size()-i-1))){
return false;
}
}
return true;
}

方法4:双端队列(入队后两端同时出队)

public boolean isPail (ListNode head) {
if (head == null || head.next == null) {
return false;
}
Deque deque = new ArrayDeque<>();
while (head != null) {
deque.addLast(head.val);
head = head.next;
}
while (deque.size() > 1) {
if (!deque.pollFirst().equals(deque.pollLast())) {
return false;
}
}
return true;
}

11、NC82 滑动窗口的最大值

public ArrayList<Integer> maxInWindows(int [] num, int size)

【算法题型总结】--3、双指针_java_08

 

 解法1:双指针

//经典双指针问题
import java.util.*;
public class Solution {
public ArrayList maxInWindows(int [] num, int size) {
ArrayList list = new ArrayList();
if(num.length == 0 || size < 1 || size > num.length) return list;
int left = 0, right = size - 1;
//在窗口中遍历求最大值并插入list,然后左右指针同时右移
while(right < num.length){
int max = num[left];
for(int i = left; i <= right; i++){
max = Math.max(max,num[i]);
}
left += 1;
right += 1;
list.add(max);
}
return list;
}
}

解法2:双端队列

import java.util.*;
public class Solution {
public ArrayList maxInWindows(int [] num, int size) {
ArrayList res = new ArrayList();
if(size<=0||num.length == 0) return res;
/**
维护一个双端队列,里面从first到last存储的是滑动窗口里的值的降序排列的下标
*/
Deque queue = new LinkedList();
for(int i=0;i /**
如果当前加入的这个数大于了队列末尾的数,则一直弹出来,最后再加入末尾
*/
while(!queue.isEmpty()&&num[queue.getLast()] queue.pollLast();
}
queue.addLast(i);
/**
根据当前下标以及滑动窗口的大小看看first是否过期,过期了就删除
*/
if(queue.getFirst() == i-size){
queue.pollFirst();
}
/**
前几个元素不满足滑动窗口的大小,不加入,后面再加入
*/
if(i>=size-1){
res.add(num[queue.getFirst()]);
}
}
return res;
}
}

解法3:优先队列

import java.util.*;
public class Solution {
public ArrayList maxInWindows(int [] num, int size) {
ArrayList list = new ArrayList<>();
if(size>num.length || size==0)
return list;
PriorityQueue qu = new PriorityQueue<>(new Comparator(){
public int compare(Integer o1 ,Integer o2){
return o2-o1;
}
});
for(int i=0;i qu.add(num[i]);
}
list.add(qu.peek());
qu.remove(num[0]);
for(int i=size;i qu.add(num[i]);
list.add(qu.peek());
qu.remove(num[i-size+1]);
}
return list;
}
}

12、NC28 最小覆盖子串

【算法题型总结】--3、双指针_i++_09

 

 public String minWindow (String S, String T)

解法1:滑动窗口

这道题的思路是:
1) begin开始指向0, end一直后移,直到begin - end区间包含T中所有字符。
记录窗口长度d
2) 然后begin开始后移移除元素,直到移除的字符是T中的字符则停止,此时T中有一个字符没被
包含在窗口,
3) 继续后移end,直到T中的所有字符被包含在窗口,重新记录最小的窗口d。
4) 如此循环知道end到S中的最后一个字符。
时间复杂度为O(n)
public class Solution {
public String minWindow(String S, String T) {
int[] map = new int[128];
//init map, 记录T中每个元素出现的次数
for(int i = 0; i < T.length(); i++) {
map[T.charAt(i)]++;
}

// begin end两个指针指向窗口的首位,d记录窗口的长度, counter记录T中还有几个字符没被窗口包含
int begin = 0, end = 0, d = Integer.MAX_VALUE, counter = T.length(), head = 0;
// end指针一直向后遍历
while(end < S.length()) {
// map[] > 0 说明该字符在T中出现,counter-- 表示对应的字符被包含在了窗口,counter--, 如果s中的字符没有在T中出现,则map[]中对应的字符-1后变为负值
if(map[S.charAt(end++)]-- > 0) {
counter--;
}
// 当counter==0时,说明窗口已经包含了T中的所有字符
while (counter == 0) {
if(end - begin < d) {
d = end - (head = begin);
}
if(map[S.charAt(begin++)]++ == 0) { // begin开始后移,继续向后寻找。如果begin后移后指向的字符在map中==0,表示是在T中出现的,如果没有出现,map[]中的值会是负值。
counter++; // 在T中的某个字符从窗口中移除,所以counter++。
}
}
}
return d==Integer.MAX_VALUE ? "" :S.substring(head, head+d);
}
}

【算法题型总结】--3、双指针_java_10

 

 13、划分链表

【算法题型总结】--3、双指针_滑动窗口_11

 

 public ListNode partition (ListNode head, int x)

方法:两个链表相连

public ListNode partition (ListNode head, int x) {
// write code here
ListNode xiao=new ListNode(0);
ListNode xiaotmp=xiao;
ListNode da=new ListNode(0);
ListNode datmp=da;

while (head!=null){
if (head.val xiaotmp.next=new ListNode(head.val);
xiaotmp=xiaotmp.next;
}
else {
datmp.next=new ListNode(head.val);
datmp=datmp.next;
}
head=head.next;
}
xiaotmp.next=da.next;
return xiao.next;
}

 

作者:哥们要飞​