デュアルポインタアルゴリズムは、非常に賢いと感じることがあり、多くの問題を解決します。要約する必要があります。まず、2ポインタは非常に広い概念であり、トラバーサルと似ていますi 和 j
が、2つのポインタがで移動する点が異なります。同時に、つまり、からO(N)
への複雑さには寄与しないO(N*N)
ため、多くのアルゴリズムリーダーから賞賛されているため、この誘導に基づいて、デュアルポインタの一般的なソリューションとルーチンを要約します。
1.質問タイプの誘導
質問には次の3種類があります。
高速ポインターと低速ポインター(前後に同期されていない2つのポインターを押します)
前面と背面のダブルポインター(1つは頭に、もう1つは尾に、中央に近づきます)
固定間隔ポインター(間隔がi、i + kの2つのポインター)
前述のように、これら3つのポインターは、配列を1回トラバースすることで完了でき、時間計算量は、以下O(N)
であり、スペース計算量はO(1)
2つのポインターのみが格納されるためです。
2.一般的な質問の種類
2.1高速ポインタと低速ポインタ
かなり古典的な質問:
- リンクリストにリングがあるかどうかを確認します-
異なるペースで2つのポインターを通過し、ポインターが一致するまで次々に移動します
https://leetcode.com/problems/linked-list-cycle/description、コードスニペットは次のとおりです。
public boolean hasCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (slow != null && fast != null) {
ListNode n = fast.next;
fast = n == null ? null : n.next;
if (slow == fast) {
return true;
}
slow = slow.next;
}
return false;
}
- 繰り返される複数形を探し、配列から繰り返される整数を見つけます:https://leetcode-cn.com/problems/find-the-duplicate-number/
コードは次のように解決されます。
public int findDuplicate(int[] nums) {
// 将其看成是一个循环的链表,快慢指针循环
int index1 = 0;
int index2 = 0;
do
{
index1 = nums[index1];
index2 = nums[index2];
index2 = nums[index2];
}while (nums[index1] != nums[index2]);
index1 = 0;
// 找出在哪个位置为起始点,可证必定在圆圈起点相遇
while(index1 != index2){
index1 = nums[index1];
index2 = nums[index2];
}
return index1;
}
2.2フロントエンドポイントポインターとバックエンドポイントポインター
- 二分探索
二分探索は、フロントポインタとバックポインタを持つ典型的な質問タイプです。コードは次のとおりです。
public static int binarySearch(int[] array, int targetElement) {
int leftIndex = 0, rightIndex = array.length - 1, middleIndex = (leftIndex + rightIndex) / 2;
while(leftIndex <= rightIndex) {
int middleElement = array[middleIndex];
if(targetElement < middleElement) {
rightIndex = middleIndex - 1;
}else if(targetElement > middleElement) {
leftIndex = middleIndex + 1;
}else {
return middleIndex;
}
middleIndex = (leftIndex + rightIndex) / 2;
}
return -1;
}
2.3一定間隔のポインタ
// 快指针q每次走2步,慢指针p每次走1步,当q走到末尾时p正好走到中间。
class Solution {
public ListNode middleNode(ListNode head) {
ListNode p = head, q = head;
while (q != null && q.next != null) {
q = q.next.next;
p = p.next;
}
return p;
}
}
- リンクリストの下部からk番目の要素を見つけますhttps://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/
// 快慢指针,先让快指针走k步,然后两个指针同步走,当快指针走到头时,慢指针就是链表倒数第k个节点。
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode frontNode = head, behindNode = head;
while (frontNode != null && k > 0) {
frontNode = frontNode.next;
k--;
}
while (frontNode != null) {
frontNode = frontNode.next;
behindNode = behindNode.next;
}
return behindNode;
}
3.テンプレートの概要
3つのコードを読んだ後、それは非常に簡単だと思いますか?これが3つのダブルポインターコードテンプレートの要約です
// 1.快慢指针
l = 0
r = 0
while 没有遍历完
if 一定条件
l += 1
r += 1
return 合适的值
//2. 左右端点指针
l = 0
r = n - 1
while l < r
if 找到了
return 找到的值
if 一定条件1
l += 1
else if 一定条件2
r -= 1
return 没找到
//3. 固定间距指针
l = 0
r = k
while 没有遍历完
自定义逻辑
l += 1
r += 1
return 合适的值
Wu Xie、Xiao San Ye、バックグラウンドの小さな新人、ビッグデータ、人工知能。もっと注意してください