双指针技巧总结--力扣 141.环形链表 142.环形链表II 167.两数之和 II - 输入有序数组 344.反转字符串 19.删除链表倒数第 N 个元素 876. 链表的中间结点

双指针技巧总结

参考:https://labuladong.gitee.io/algo/2/21/53/ -- labuladong 的算法小抄

快慢指针

主要解决链表中的问题,比如典型的判定链表中是否包含环

1、判定链表中是否含有环

力扣141. 环形链表

经典解法就是用两个指针,一个跑得快,一个跑得慢。如果不含有环,跑得快的那个指针最终会遇到 null,说明链表不含环;如果含有环,快指针最终会超慢指针一圈,和慢指针相遇,说明链表含有环。

boolean hasCycle(ListNode head) { ListNode fast, slow; fast = slow = head; while (fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; if (fast == slow) return true; } return false; }

注意 fast.next!=null, 因为fast要为next.next

方法2: 可以用hash表的方式,访问过的放在hash表里。

public class Solution { public boolean hasCycle(ListNode head) { Set<ListNode> seen = new HashSet<ListNode>(); while (head != null) { if (!seen.add(head)) { return true; } head = head.next; } return false; } }

Set<ListNode> seen = new HashSet<ListNode>();

力扣142-环形链表找节点

证明:

img

证明过程:b为环节点数,a为非环节点数。f为快指针步数,s为慢指针步数,快2慢1,f=2s,f=s+nb,n为圈数。快慢第一次相遇时,有2s=s+nb,推出s=nb(即多走的为b的n倍)。

又到环节的的步数 k = a+nb 一定成立。此时s已经在nb了,再走a步就是k点了,重置快指针/慢指针为head(都行的),此时快指针一步一步走,走a步,一定也会到k点,因此,此时快慢第二次相遇,一定是k点。

易错点:循环判断条件中不要进行fast == slow的判断,因为两者都是从head出发,就会达到退出循环的条件,应该把判断相等放在循环中 --可用do while

如何判断环的长度:找到头节点后,再走一遍

public class Solution { public ListNode detectCycle(ListNode head) { ListNode fast, slow; fast = slow = head; while(fast!=null && fast.next!=null){ //fast.next!=null && fast.next.next!=null 这里的条件写错了 fast=fast.next.next; slow=slow.next; if(fast==slow) break; } if(fast==null || fast.next==null){ //条件错了,不是fast==null || slow==null,要和上面一样 return null; } fast=head; while(fast!=slow){ fast=fast.next; //这里错了,不是fast.next.next; slow=slow.next; } return slow; } }

三处错误

寻找链表的中点--力扣876

快指针到终点,慢指针到达中间。

注意:当链表的长度是奇数时,slow恰巧停在中点位置;如果长度是偶数,slow 最终的位置是中间偏右:

img
class Solution { public ListNode middleNode(ListNode head) { ListNode fast,slow; fast=slow=head; while(fast!=null && fast.next!=null){ fast=fast.next.next; slow=slow.next; } return slow; } }

寻找链表中点的一个重要作用是对链表进行归并排序

两种简单的方法:一个是放到数组里面,一个是遍历两次

力扣19--寻找链表的倒数第 n个元素

思想: 前一个指针先走n步,然后一起走,这样快的到了根节点慢的就是倒数n,注意此时要快节点走到null前一个停止,便于删除

注意点: 要注意只有一个节点的情况考虑删除第一个节点时的情形,直接返回head.next

public ListNode removeNthFromEnd(ListNode head, int n) { ListNode fast, slow; fast = slow = head; while (n-- > 0) { fast = fast.next; } if (fast == null) { //注意考虑特殊情况。 // 如果此时快指针走到头了, // 说明倒数第 n 个节点就是第一个节点 return head.next; } while (fast != null && fast.next != null) { //注意这里是走不到末尾的,只能走到最后一个节点,这样slow的next就是真正的倒数第n个 fast = fast.next; slow = slow.next; } // slow.next 就是倒数第 n 个节点,删除它 slow.next = slow.next.next; return head;

技巧:可以使用dummy节点,该节点指向头节点,返回时也可以返回dummy.next

也可以用栈, 递归的方法也很巧妙,算长度时倒数第n个

左右指针

后者主要解决数组(或者字符串)中的问题,比如二分查找

1、二分查找,再具体看

2、力扣167-两数之和

class Solution { public int[] twoSum(int[] numbers, int target) { int left=0;int right=numbers.length-1; //错误,不用length(),不用加() while(left<right){ if(numbers[left]+numbers[right]==target){ return new int[] {left+1,right+1}; //如何retrun 数组,技巧 ,注意要new,new int[] {left+1,right+1 } if(numbers[left]+numbers[right]<target) { left++; } if(numbers[left]+numbers[right]>target) { right--; } } return null; } }

两个地方出错

其他方法:二分查找

补充:

1、

给你一个array [1, 9, 134 , 10, 25 , 40, 4, 7],

给一个target,返回所有 A+B=target 的 (paire 对) 上面比如是target = 11 , 返回 [(1, 10), (4, 7)], 每个元素只能用一次 腾讯面试,167题的变形,同时说出时间复杂度和空间复杂度

感觉还是这个题的思路吧,唯一不同的是sum = target后不结束,而是双指针同时移动,继续遍历直到L,可以先排序?

java public static List<List<Integer>> find(int[] array,int target){ List<List<Integer>> ans=new LinkedList<>(); HashMap<Integer,Integer> map=new HashMap<>(); for(int i=0;i<array.length;i++){ int diff=target- array[i]; if(map.containsKey(diff)) { Integer[] temp={i,map.get(diff)}; ans.add(Arrays.asList(temp)); } //数组转化为l map.put(array[i],i); } return ans; }

2、

稍微变形,与target差距最小的两数

3、反转数组--力扣344

简单题

void reverseString(char[] arr) { int left = 0; int right = arr.length - 1; while (left < right) { // 交换 arr[left] 和 arr[right] char temp = arr[left]; arr[left] = arr[right]; arr[right] = temp; left++; right--; } }

4、滑动窗口算法


__EOF__

本文作者userName
本文链接https://www.cnblogs.com/Blunt-Raz0r/p/15507432.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Blunt-Razor  阅读(70)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示