兩個雙指針 的 “他“和“ 她“會相遇么? —— “雙指針“算法 (Java版)

本篇會加入個人的所謂魚式瘋言

??????魚式瘋言:??????此瘋言非彼瘋言
而是理解過并總結出來通俗易懂的大白話,
小編會盡可能的在每個概念后插入魚式瘋言,幫助大家理解的.
🤭🤭🤭可能說的不是那么嚴謹.但小編初心是能讓更多人能接受我們這個概念 !!!

在這里插入圖片描述

前言

因為小編最近在學習算法, 每次學習新知識,都會有新的體會和心得,就會和小伙伴們一起分享, 今天 帶來我們 算法 首篇 ————“雙指針” 算法 💥💥💥

這時就會有小伙伴問了,我們的"雙指針"算法 不是在 “題海尋offer” 專題中講解過么 ? 為啥還要重復學習呢 🤔 🤔 🤔

是的, 但這次小編帶來的是更重點更詳細并且更系統以算法的角度一步一步講解我們的 “雙指針” 算法 💖 💖 💖

目錄

  1. 雙指針算法初識

  2. 雙指針算法的運用

  3. 雙指針算法的總結

一. 雙指針初識

1. 雙指針算法的認識

首先小編在這里得區別一個概念

這里我們提及的 雙“指針” 的指針 并不是我們學過 C語言 的 定義 int * p = &a 那個指針 ,

這里我們用的指針其實就是一個 變量

我們通過 變量 來指向一個元素 然后不斷移動來影響數據的一個單純的 變量

雙指針 就是定義兩個變量來 影響數據

2. 雙指針算法的種類

常見的雙指針有兩種形式:

一種是 對撞指針,一種是 左右指針

對撞指針

? 對撞指針 從兩端向中間移動。一個指針從 最左端 開始,另一個從 最右端 開始,然后逐漸往 中間 逼近。

? 對撞指針 的終止條件一般是兩個指針 相遇=或者 錯開(也可能在循環內部找到結果直接跳出循環),也就是:

? left == right (兩個指針指向同一個位置)

? left > right (兩個指針錯開)

快慢指針

快慢指針:又稱為 龜兔賽跑算法,其基本思想就是使用兩個移動 速度不同 的指針在數組或鏈表等序列結構上移動。

這種方法對于處理 環形鏈表數組 非常有用。

其實不單單是環形鏈表或者是數組,如果我們要研究的問題出現 循環往復 的情況時,均可考慮使用 快慢指針 的思想。

快慢指針的實現方式有很多種,最常用的一種就是:

在一次循環中,每次讓慢的指針向后移動 一位 ,而快的指針往后移動 兩位,實現一快一慢

魚式瘋言

總結三句話

  1. 指針本質上是 變量, 只是形式上我們俗稱 “指針”

  2. 對撞指針 是 從起點和終點兩個 同時 相向 走,會相遇 的兩個指針

  3. 快慢指針 是 同向不相遇的兩個走的跨度不一樣的指針

二. 雙指針的算法運用

1. 復寫零

1089.復寫零題目鏈接

<1> . 題目描述

在這里插入圖片描述

給你一個長度固定的整數數組 arr ,請你將該數組中出現的每個零都復寫一遍,并將其余的元素
向右平移。
注意:請不要在超過該數組長度的位置寫入元素。請對輸入的數組就地進行上述修改,不要從函數返
回任何東西。
示例 1:
輸入: arr = [1,0,2,3,0,4,5,0]
輸出: [1,0,0,2,3,0,0,4]
解釋:
調用函數后,輸入的數組將被修改為: [1,0,0,2,3,0,0,4]

題目的 含義

在這個數組中,我們 從左往右 ,每出現一個0 就在右邊位置再 寫一個 0 ,然后數據一直 挪動 , 原有數據就要一直往右 挪動

<2>. 講解算法原理

大體思路 分為 :

如果 「從前向后」 進行原地復寫操作的話,由于 0 的出現會 復寫兩次 ,導致沒有復寫的數 「被覆
蓋掉」
。因此我們選擇 「從后往前」 的復寫策略。

但是 「從后向前」 復寫的時候,我們需要找到 `「最后一個復寫的數」 `` ,因此我們的大體流程分兩
步:

算法流程

  • 先找到最后一個復寫的數

請添加圖片描述

  1. 先定義一個 cur=0dest= -1 指針來 通向移動
  1. 先讓 cur 向前走一步 , 當 cur 位置遇到 值 為 0 時就 dest 就走 兩 步

3,否則讓 dest 走一步 ,直到 dest 到底 數組下標 >= n- 1 的位置就停止

  • 然后從后向前進行復寫操作。

請添加圖片描述

  1. cur 遇到 0 時 ,就讓 dest 跳躍兩次 并 把這兩次的值都賦值為 0cur 走一步
  1. cur 不是 0 時 ,就把 cur 的值賦給 dest , 接著讓 dest 和 cur 都走一步

<3>. 編寫代碼

class Solution {public static void duplicateZeros(int[] arr) {int cur=0;int dest=-1;int n=arr.length;while (cur < n) {if (arr[cur]==0) {dest +=2;} else {dest++;}if (dest >= n-1) {break;}cur++;}if (dest > n-1) {arr[n-1]=0;cur--;dest-=2;}while (cur >= 0) {if (arr[cur]==0) {arr[dest--]=0;arr[dest--]=0;cur--;} else {arr[dest--]=arr[cur--];}}}}

在這里插入圖片描述

魚式瘋言

說兩句小編關于本題自己的理解和體會

  1. 這里我們用到了 前后指針(快慢指針) , 一個 快指針 模擬 復寫零 后的數組的位置 , 而 慢指針 用于 模擬 == 未復寫零后的數組的最后一個元素的位置
  1. 細節
   if (dest > n-1) {arr[n-1]=0;cur--;dest-=2;}

當 == dest== 的位置跳到 n 的位置時, 說明 0 的位置不夠放 , 我們就需要 把最后一個位置 賦值為 0
并讓 dest 想左走兩步, cur 走一步即可

2. 快樂數

202. 快樂數題目鏈接

<1>. 題目描述

在這里插入圖片描述

編寫一個算法來判斷一個數 n 是不是快樂數。

「快樂數」 定義為:

? 對于一個正整數,每一次將該數替換為它每個位置上的數字的平方和。

? 然后重復這個過程直到這個數變為 1,也可能是無限循環但始終變不到 1 。

? 如果這個過程 結果為 1 ,那么這個數就是快樂數。

? 如果 n 是 快樂數 就返回 true ;不是,則返回 false 。

示例 1:
輸入: n = 19
輸出: true
解釋:
19 -> 1 * 1 + 9 * 9 = 82
82 -> 8 * 8 + 2 * 2 = 68
68 -> 6 * 6 + 8 * 8 = 100
100 -> 1 * 1 + 0 * 0 + 0 * 0 = 1

示例 2:
輸入: n = 2
輸出: false
解釋:(這里省去計算過程,只列出轉換后的數)
2 -> 4 -> 16 -> 37 -> 58 -> 89 -> 145 -> 42 -> 20 -> 4 -> 16

往后就不必再計算了,因為出現了重復的數字,最后結果肯定不會是1

題目含義:

讓一個數一直取出每個位置上的數字的 平方算出他們的之和 ,得到這個數后 判斷是否為 1

如果為 1 說明是快樂數 返回 true

如果繼續循環的按照上面的方法計算知道 得到看是否 最終結果為 1= ,若不是就返回 false

<2>. 講解算法思想

我們先簡單的分析一下

為了方便敘述,將「對于一個正整數,每一次將該數替換為它每個位置上的數字的平方和」這一個
操作記為 x 操作;

題目告訴我們,當我們不斷重復 x 操作的時候,計算一定會 「死循環」 ,死的方式有 兩種

? 情況一:一直在 1死循環 ,即 1 -> 1 -> 1 -> 1…

請添加圖片描述

? 情況二:在歷史的數據中死循環,但始終變不到 1

請添加圖片描述

由于上述兩種情況只會出現一種

因此,只要我們能確定循環是在 「情況一」 中進行

還是在 「情況二 ] 中進行,就能得到結果。

大體的算法思想

先用一個方法來 獲取到每一位上數字的 平方之和

由于我們在循環內查找這個數 (相當于檢查一個鏈表是否成環) , 所以我們第一步考慮的應該是 快慢指針 的思維,

我們進行利用 定義 一個 left 的單位為 1 走一步, 再定義一個 right 單位為 2 走兩步 ,因為是環形所以 最終是一定會相遇的

最后一步 我們只需要在相遇的位置判斷是否是 等于 1 即可

請添加圖片描述

<3>. 編寫代碼

class Solution {public boolean isHappy(int n) {int slow=n;int fast=happyFunc(n);// 一定會成環的while(slow != fast) {slow = happyFunc(slow);fast = happyFunc(happyFunc(fast));}// 最終相遇時只要為 1 就為快樂數if(slow==1) {return true;}return false;}private int happyFunc(int n) {int sum=0;while(n != 0) {int t = n % 10;sum += (t*t);n /= 10; }return sum;}}

在這里插入圖片描述

魚式瘋言

先說幾點體會吧

  1. 當我們碰到 一個成環或者循環 的一種結構時, 快慢指針的思路是很有必要去嘗試的
  1. 本題 的 特點 最終是會成為一個 特定的值 , 我們只需要循環判斷即可
  1. 本題細節
int slow=n;int fast=happyFunc(n);

初始化的時候

不可以讓 fast 和 slow 同時為 n ,否則就進入不了 循環 .

3. 查找總價值 為目標值的兩個商品

179. 查找總價值為目標值的兩個商品題目鏈接

<1>. 題目描述

在這里插入圖片描述

輸入一個 遞增 排序的數組和一個數字s ,在數組中查找兩個數,使得它們的和正好是s 。如果有多
對數字的和等于s ,則輸出 任意一對 即可。

示例 1:
輸入: nums = [2,7,11,15], target = 9
輸出: [2,7] 或者 [7,2]

題目含義 就是找兩個和為 s 的數字

<2>. 講解算法思想

題目分析

如果我們要求兩個數的 ,只需要先 固定 一個數,然后再 尋找其他數 判斷即可尋找到

暴力枚舉

兩層 for 循環列出所有兩個數字的組合,判斷是否等于目標值。

雙指針 的思路

當我們看到 一個有序數組的時候, 我們頭腦中就得建立兩個思路 :

一個 二分查找 算法

一個 雙指針 算法

而在本題中更適合用我們的雙指針來解決 兩數和 的問題

  1. 先定義一個指針為 left = 0 , 另一個指針為 right = n-1
  1. leftright 的 數值之和 > target 時 ,我們就讓 較大值 right --

left 和 right 的數組之和 < target 時, 我們就讓較小值 left ++ ;

直到最終相遇或者尋找到目標值 target 為止 ,

請添加圖片描述

<3>. 編寫代碼

class Solution {public int[] twoSum(int[] price, int target) {int right=price.length-1;int left=0;int []ret=new int[2];while(left < right) {if(price[left] +price[right] > target) {right--;} else if (price[left] +price[right] < target){left++;} else {ret[0]=price[left];ret[1]=price[right];return ret; }}  return ret; }
}

在這里插入圖片描述

魚式瘋言

記住一點

有序就要想到用 二分查找算法 或者 雙指針算法

4 有效三角形個數

611.有效三角形個數題目鏈接

<1>. 題目描述

在這里插入圖片描述

給定一個包含非負整數的數組 nums ,返回其中可以組成三角形三條邊的三元組個數。

示例 1:

輸入: nums = [2,2,3,4]
輸出: 3
解釋:有效的組合是:
2,3,4 (使用第一個 2)
2,3,4 (使用第二個 2)
2,2,3

示例 2:

輸入: nums = [4,2,3,4]
輸出: 4

題目含義 :

找出所有能滿足 組合 三角形三條邊 的個數(包含相同數字的邊)

<2>. 講解算法思想

題目分析

如果我們要找三條邊, 先 固定兩個數 的基礎上

再找另外一個數來判斷是否滿足 三角形三邊條件

算法過程

解法一 : 暴力枚舉

三個 for= 來查找 是否存在該數據

解法二 : 雙指針算法

先將 數組排序

根據「解法一」中的優化思想,我們可以固定一個「最長邊」,然后在比這條邊小的有序數組中找
出一個二元組,使這個二元組之和大于這個最長邊。由于數組是有序的,我們可以利用「對撞指
針」來優化。

設最長邊枚舉到 i 位置,區間 [left, right]i 位置**左邊的區間(**也就是比它小的區
間):

? 如果 nums[left] + nums[right] > nums[i]

? 說明 [left, right - 1] 區間上的所有元素均可以與 nums[right] 構成比
nums[i] 大的二元組

? 滿足條件的有 right - left

? 此時 right 位置的元素的所有情況相當于全部考慮完畢, right-- ,進入下一輪判斷

? 如果 nums[left] + nums[right] <= nums[i]

? 說明 left 位置的元素是不可能與 [left + 1, right] 位置上的元素構成滿足條件
的二元組

? left 位置的元素可以舍去left++ 進入下輪循環

請添加圖片描述

<3>. 編寫代碼

class Solution {public int triangleNumber(int[] nums) {Arrays.sort(nums);int sz = nums.length;int count=0;for(int i=sz-1; i >= 2 ; i--) {int left=0,right=i-1;while(left < right) {if(nums[left] + nums[right] > nums[i]) {count += (right-left);right--;} else {left++;}}}return count;  }
}

在這里插入圖片描述

魚式瘋言

講兩點

  1. 必須 先排序 ,利用本身的 單調性 來進行 兩個較小值和最大值進行比較來判斷

所以我們得出以下結論

有序 》 單調性 》 雙指針

三. 雙指針算法的總結

復寫零快樂數 時, 用到了(快慢指針).特別在快樂數的時候,我們在循環的特點下

我們建立了 快慢指針的思路

而在 查找兩個數之和有效三角形個數 時, 我們用到了 雙指針(對撞指針)

而在這里我們巧妙的利用 單調性 的方法來建立 對撞指針 的模型

如果覺得小編寫的還不錯的咱可支持 三連 下 (定有回訪哦) , 不妥當的咱請評論區 指正

希望我的文章能給各位寶子們帶來哪怕一點點的收獲就是 小編創作 的最大 動力 💖 💖 💖

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/20120.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/20120.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/20120.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MySQL入門學習-查詢進階.UNION

UNION操作符用于合并兩個或多個SELECT語句的結果集。它可以將多個查詢結果合并為一個結果集&#xff0c;這在需要從多個表中獲取數據并將它們組合在一起時非常有用。下面是一個使用UNION的示例代碼&#xff1a; SELECT column1, column2,...FROM table1UNIONSELECT column1, c…

springboot kafka 提高拉取數量

文章目錄 背景問題復現解決問題原理分析fetch.min.bytesfetch.max.wait.ms源碼分析ReplicaManager#fetchMessages 背景 開發過程中&#xff0c;使用kafka批量消費&#xff0c;發現拉取數量一直為1&#xff0c;如何提高批量拉取數量&#xff0c;記錄下踩坑記錄。 問題復現 ka…

攻防對抗少丟分,愛加密幫您筑起第二防線

應用程序通常處理和存儲大量的敏感數據&#xff0c;如用戶個人信息、財務信息、商業數據、國家數據等&#xff0c;用戶量越大的應用程序&#xff0c;其需要存儲和保護的用戶數據越多。因此應用層長期是攻擊方的核心目標&#xff0c;傳統應用安全依靠防火墻(FireWall)、入侵檢測…

1.7 協議層次和服務模型

協議層次 網絡是一個復雜的系統! ? 網絡功能繁雜&#xff1a;數字信號的物理信 號承載、點到點、路由、rdt、進程區分、應用等 ?現實來看&#xff0c;網絡的許多構成元素和設備: ? 主機 ? 路由器 ? 各種媒體的鏈路 ? 應用 ? 協議 ? 硬件, 軟件 Q:如何組織和實現這個…

Linux上實現ssh免密通訊

Linux上實現ssh免密通訊 1.SSH互信原理2.SSH所需的RPM包3.兩臺機器實現互信4.常見問題及處理 1.SSH互信原理 SSH&#xff08;Secure Shell&#xff09;是一種安全的傳輸協議&#xff0c;它能讓Linux系統中的服務器和客戶端之間進行安全可靠的通訊。 SSH使用加密的傳輸方式&…

iOS組件化 方案 實現

iOS組件化 組件化的原因現在流行的組件化方案方案一、url-block &#xff08;基于 URL Router&#xff09;方案二、protocol調用方式解讀 方案三、target-action調用方式解讀 gitHub代碼鏈接參考 組件化的原因 模塊間解耦模塊重用提高團隊協作開發效率單元測試 當項目App處于…

網絡原理-四

一、續 當窗口大小為0,意味著緩沖區滿了,此時發送方,就因該暫停發送,發送方會周期性的除法 " 窗口探測包 " ,并不攜帶載荷,這樣的包對于業務不產生影響,只是為了觸發ACK,一旦查詢出來的結果是非0,緩沖區右有空間了,發送方就可以繼續發送. 二、擁塞控制 要限制發送方…

一步一步寫線程之十三隊列間的消息通知

一、線程和分布式的通信 隨著技術的不斷發展&#xff0c;多線程和分布式通信愈發的普及。那么在這種場景下的如何進行數據的通信&#xff0c;便成為了一個非常典型的問題。無論是多線程還是分布式&#xff0c;其實其抽象出來的通信機制都是類似的。或者說換句話&#xff0c;多…

java檢測字符串是否包含數字和字母

在Java中&#xff0c;要檢測一個字符串是否同時包含數字和字母&#xff0c;我們可以使用正則表達式&#xff08;regex&#xff09;或者通過遍歷字符串并檢查每個字符來實現。以下是兩種方法的詳細代碼示例&#xff1a; 1.方法一&#xff1a;使用正則表達式 import java.util.…

【AI+知識庫問答】沉浸式體驗了解 AI知識庫問答fastGPT

之前寫過一篇文章 【AI本地知識庫】個人整理的幾種常見本地知識庫技術方案 &#xff0c; 由于當時主要是針對AI本地知識庫&#xff0c; 所以沒列fastGPT。 最近經常刷到fastGPT&#xff0c;這里單獨水一篇。 FastGPT 是一個基于 LLM 大語言模型的知識庫問答系統&#xff0c;…

Github 2024-06-01 開源項目日報Top10

根據Github Trendings的統計,今日(2024-06-01統計)共有10個項目上榜。根據開發語言中項目的數量,匯總情況如下: 開發語言項目數量Python項目5Jupyter Notebook項目2TypeScript項目1Go項目1Shell項目1Lua項目1Kong:云原生API網關與AI能力 創建周期:3482 天開發語言:Lua協議…

如何確保績效目標執行到位?

很多企業在實施績效過程中&#xff0c;盡管制定好了績效目標&#xff0c;但是沒有執行下去&#xff0c;管理者將原因歸咎于“員工低效”、“體制機制”等問題&#xff0c;那么在人力資源管理方面&#xff0c;企業應該如何確保制定的績效目標執行到位&#xff1f;如何提高低效能…

云原生架構相關技術_4.服務網格

1.技術特點 服務網格&#xff08;ServiceMesh&#xff09;是分布式應用在微服務軟件架構之上發展起來的新技術&#xff0c;旨在將那些微服務間的連接、安全、流量控制和可觀測等通用功能下沉為平臺基礎設施&#xff0c;實現應用與平臺基礎設施的解耦。這個解耦意味著開發者無需…

React@16.x(14)context 舉例 - Form 表單

目錄 1&#xff0c;目標2&#xff0c;實現2.1&#xff0c;index.js2.2&#xff0c;context.js2.2&#xff0c;Form.Input2.3&#xff0c;Form.Button 3&#xff0c;使用 1&#xff0c;目標 上篇文章說到&#xff0c;context 上下文一般用于第3方組件庫&#xff0c;因為使用場景…

Chisel入門——在windows下vscode搭建|部署Scala2.13.3開發環境|用Chisel點亮FPGA小燈等實驗

文章目錄 前言一、vscode搭建scala開發環境1.1 安裝Scala官方插件1.2 創建hello_world.scala文件1.3 確認java的版本(博主使用的是1.8)1.4 下載Scala Windows版本的二進制文件1.5 配置環境變量1.6 交互模式測試一下1.7 vscode運行scala 二、windows安裝sbt2.1 下載sbt2.2 設置環…

函數遞歸及具體例子(持續更新)

遞歸就是函數自己調用自己 求n的階乘 n! n * (n - 1)! 直到n為1或者0的時候為止 舉個例子 int Fun(int n) {if (n < 0){return 1;}else{return n * Fun(n - 1);} }int main() {int n 0;scanf("%d", &n);int ret Fun(n);printf("%d\n", ret…

安裝Kubernetes v3 ----以docker的方式部署

以docker的方式部署 docker run -d \ --restartunless-stopped \ --namekuboard \ -p 80:80/tcp \ -p 10081:10081/tcp \ -e KUBOARD_ENDPOINT"http://192.168.136.55:80" \ -e KUBOARD_AGENT_SERVER_TCP_PORT"10081" \ -v /root/kuboard-data:/data \ e…

springboot中抽象類無法注入到ioc容器

1、背景 在寫代碼時&#xff0c;發現service接口有兩個實現類&#xff0c;并且兩個實現類中沒有對類名重命名&#xff0c;屬性注入的時候也沒有使用byName或Qualifier&#xff0c;正確情況下會發生多實現報錯的問題&#xff0c;以前對這個問題進行解析過。 2、調試過程 我想…

【設計模式】創建型-建造者模式

前言 在面向對象的軟件開發中&#xff0c;構建復雜對象時經常會遇到許多挑戰。一種常見的解決方案是使用設計模式&#xff0c;其中建造者模式是一個強大而靈活的選擇。本文將深入探討建造者模式的原理、結構、優點以及如何在實際項目中應用它。 一、復雜的對象 public class…

飛凌嵌入式FET3568/3568J-C核心板現已適配OpenHarmony4.1

近日&#xff0c;飛凌嵌入式為FET3568/3568J-C核心板適配了OpenHarmony4.1系統&#xff0c;新系統的加持使核心板在兼容性、穩定性與安全性等方面都得到進一步提升&#xff0c;不僅為FET3568/3568J-C核心板賦予了更強大的功能&#xff0c;也為開發者們提供了更加廣闊的創新空間…