文章目录
- 1、双指针算法
- 1.1 对撞双指针
- 1.2 快慢双指针
- 2、leetcode141:环形链表
- 3、leetcode881:救生艇
1、双指针算法
用两个指针来共同解决一个问题:
1.1 对撞双指针
比如先有一个有序的数组array
int[] array = {1, 4, 5, 7, 9}
先要找两个数,使得其和为12,且两个数不能相同。最先想到的是,两层循环,遍历array,如外层 i = 1,内层循环 j = 4 5 7 9,外层 i = 4,内层循环 j = 1 5 7 9……,但这样时间复杂度为O(n^2)。用对撞双指针优化:
对撞前即p1 <= p2,p1 = p2时,说明二者指向同一个元素,再往下就错开了。
1.2 快慢双指针
比如现在要检测一个链表是否为环形:
此时可用快慢双指针,慢的一次走一步,s = s.next,快的一次走两步,f = f.next.next,二者同时从队首出发:
移动三次后,快慢指针相遇了,这说明是个环形,否则二者不会相遇。
2、leetcode141:环形链表
和上面的快慢指针一样,代码实现:
public class P141 {
public static boolean checkCycle(ListNode head) {
if (null == head) {
return false;
}
// 快慢指针,均从头节点开始
ListNode slowPoint = head;
ListNode fastPoint = head;
// 这里的条件无需判断慢指针,如果是环形,大家都不为null
// 如果不是环形,那一定是快指针先走完而出现null
// 因此退出循环的条件是:快指针走完了,而快指针一次两步,所以走完的条件是当前已为空或者不够两步了
while(fastPoint != null && fastPoint.next != null) {
// 慢指针一次一步,快指针一次两步
slowPoint = slowPoint.next;
fastPoint = fastPoint.next.next;
if (slowPoint.equals(fastPoint)){
return true;
}
}
return false;
}
}
测试:
//链表节点类
public class ListNode {
int val;
ListNode next;
public ListNode() {
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
@Override
public String toString() {
return "ListNode{" +
"val=" + val +
", next=" + next +
'}';
}
}
public class P141 {
public static void main(String[] args) {
ListNode tailNode = new ListNode(1, null);
ListNode node4 = new ListNode(2, tailNode);
ListNode node3 = new ListNode(2, node4);
ListNode node2 = new ListNode(1, node3);
ListNode node1 = new ListNode(0, node2);
ListNode head = new ListNode(9, node1);
tailNode.setNext(head);
System.out.println(checkCycle(head));
}
}
3、leetcode881:救生艇
其实本质是两个人的体重之和问题,和上面提到的对撞指针很像,不过一个是等号,一个是小于号,因此考虑先给所有人的体重从小到大排个序(因为排序是对撞指针移动的基础前提)
public class P881 {
public static int calcMinShipNum (int[] weight, int limit) {
if (weight == null || weight.length == 0 || limit <= 0) {
return 0;
}
Arrays.sort(weight);
// 头尾指针的位置
int i = 0;
int j = weight.length - 1;
// 船的数量
int res = 0;
while (i <= j) {
if (weight[i] + weight[j] < limit) {
// 两个人可以乘一条船走,船的数量+1,头指针向右一位,尾指针向左一位
i = i + 1;
j = j - 1;
} else {
// 两个人体重总和超重,只让最胖的人走
j = j - 1;
}
// 不管这轮是载走了首位两个人,还是只能带走最胖的那个人,船的数量都+1
res = res + 1;
}
return res;
}
}
测试:
public class P881 {
public static void main(String[] args) {
int[] weightArray = {3,5,3,4};
System.out.println(calcMinShipNum(weightArray, 5));
}
}