Java双指针技巧
2022/1/15 20:33:41
本文主要是介绍Java双指针技巧,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
在我们练习Java算法的时候,难免会遇到一些题目利用一些技巧性的解题方法比不用要强很多,这次主要分享一下有关双针的技巧。
双指针一般分为两类:一类是快慢指针,一类是左右指针。前者解决主要链表中的问题,比如典型的判断链表中是否包含环;后者主要解决数组(或字符串)中的问题,比如二分查找。
一、快慢指针
1. 判断链表中是否含有环
链表中要想不含环,那么这个指针最终会遇到空指针 null
表示链表到头了,这还好说,可以判断该链表不含环
boolean hasCycle(ListNode head) { while (head != null) { head = head.next; } return false; }
如果链表中存在环了,那么上述的代码就会陷入死循环,因为环形数组中没有 null
指针作为尾部节点。
经典解法就是用两个指针,一个跑的快,一个跑的慢,如果不含有环,跑的快的那个指针最终会遇到 null
,说明链表不含有环。如果快指针最终会超满指针一圈,和慢指针相遇,说明链表含有环。
boolean hasCycle(ListNode head) { ListNode fast = head, slow = head; while (fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; // 如果两个指针相遇,说明构成了环,返回 true if (fast = slow) { return true; } } return false; }
2. 已知链表中含有环,返回这个环的起止位置
ListNode detectCycle(ListNode head) { ListNode fast = head, slow = head; while (fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; if (slow = fast) { break; } } if (fast == null || fast.next == null) { // fast 没有遇到环,遇到了空指针 return null; } slow = head; while (slow != fast) { slow = slow.next; fast = fast.next; } return slow; }
当快慢指针相遇的时候,让其中一个指针指向头节点,然后再让快慢指针以相同的速度前进,再次相遇的时候,就是环开始的位置。
解释:
第一次相遇时,假设慢指针 slow
走了 k
步,那么快指针 fast
一定走了 2k 步;
fast
一定比 slow
多走了 k
步,这多走的 k
步其实就是 fast
指针在环里转圈圈,所以 k
的值就是环长度的整数倍。
假设相遇点距离环的起点的距离为 m
,那么环的起点距头节点 head
的距离就是 k - m
,也就是说如果从 head
前进 k - m
步就能到达环起点。
巧的是,如果从相遇点继续前进 k - m
步,也恰好到达环起点,甭管 fast
在环里转了几圈,走 k
步到相遇点,那走 k - m
步一定就是走到环起点了
所以,只要我们把快慢指针中的任一重新指向 head
,然后两个指针同速前进,k - m
步就会相遇,相遇之处就是环的起点了。
二、左右指针
左右指针在数组中实际上是指两个索引值,一般初始化为 left = 0, right = nums.length - 1
1. 二分查找
int binarySearch(int[] nums, int target) { int left = 0, right = nums.length - 1; while (left <= right) { int mid = (right + left) / 2; if (nums[mid] == target) { return mid; } if (nums[mid] > target) { right = mid - 1; } else if (nums[mid] < target) { left = mid + 1; } } return - 1; }
2. 两数之和
只要数组有序,我们就应该想到双指针的技巧,
int[] twoSum(int[] nums, int target) { int left = 0, right = nums.length - 1; while (left < right) { int sum = nums[left] + nums[right]; if (sum == target) { return new int[]{left, right} } else if (sum < target) { // 让 sum 大一些 left++; } else if (sum > target) { // 让 sum 小一些 right--; } } return new int[]{-1, -1}; }
3. 数组反转
反转一个 char[]
类型的字符串数组
void reverseString(char[] arr) { int left = 0, right = arr.length - 1; while (left <= right) { arr[left] = arr[left] + arr[right]; arr[right] = arr[left] - arr[right]; arr[left] = arr[left] - arr[right]; left++; right--; } }
如果这几个例子可以掌握了,那么双指针基本的思想,以及链表等基本操作也就可以掌握了,掌握了基本的技巧,还需要经过做一些题目进行打磨,多写一些题目会更加深刻的理解。
这篇关于Java双指针技巧的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-12百万架构师第十五课:源码分析:Spring 源码分析:SpringMVC核心原理及源码分析|JavaGuide
- 2025-01-11有哪些好用的家政团队管理工具?
- 2025-01-11营销人必看的GTM五个指标
- 2025-01-11办公软件在直播电商前期筹划中的应用与推荐
- 2025-01-11提升组织效率:上级管理者如何优化跨部门任务分配
- 2025-01-11酒店精细化运营背后的协同工具支持
- 2025-01-11跨境电商选品全攻略:工具使用、市场数据与选品策略
- 2025-01-11数据驱动酒店管理:在线工具的核心价值解析
- 2025-01-11cursor试用出现:Too many free trial accounts used on this machine 的解决方法
- 2025-01-11百万架构师第十四课:源码分析:Spring 源码分析:深入分析IOC那些鲜为人知的细节|JavaGuide