算法-雙指針問題解決思路

算法中的雙指針使用,有時候會以爲很巧妙,解決了不少的問題,有必要概括總結一下,首先雙指針也是個很寬泛的概念,它相似於遍歷中的 i 和 j 可是其區別是,兩個指針是同時移動的,即沒有貢獻複雜度從O(N)O(N*N) ,因此被不少算法大佬所推崇,因此基於此概括總結出雙指針的常看法法和套路。算法

1.題型概括

這裏將題型概括爲三種,分別以下:數組

  • 快慢指針(先後按不一樣步調的兩個指針)
  • 先後雙端指針(一個在首,一個在尾部,向中間靠攏)
  • 固定間隔的指針(以i, i + k的間距的兩個指針)

前面講到,這三種指針都是遍歷一次數組便可完成,其時間複雜度低於或者等於O(N) ,空間複雜度是O(1) 由於就兩個指針存儲。大數據

2.常見題型

2.1快慢指針

至關經典的一道題:人工智能

  • 判斷鏈表是否有環-

經過步調不一致的兩個指針,一前一後一塊兒移動,直到指針重合了spa

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;
    }

代碼解決以下:code

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 先後首尾端點指針

  • 二分查找

二分查找是典型的先後指針的題型,代碼以下:ip

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步,而後兩個指針同步走,當快指針走到頭時,慢指針就是鏈表倒數第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. 模板總結

看完三個代碼,是否是以爲很簡單,下面總結一下三種雙指針的代碼模板leetcode

// 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 合適的值

吳邪,小三爺,混跡於後臺,大數據,人工智能領域的小菜鳥。
更多請關注
fileget

相關文章
相關標籤/搜索