位運算題目:尋找重復數

文章目錄

  • 題目
    • 標題和出處
    • 難度
    • 題目描述
      • 要求
      • 示例
      • 數據范圍
      • 進階
  • 前言
  • 解法一
    • 思路和算法
    • 代碼
    • 復雜度分析
  • 解法二
    • 思路和算法
    • 代碼
    • 復雜度分析
  • 解法三
    • 思路和算法
    • 代碼
    • 復雜度分析

題目

標題和出處

標題:尋找重復數

出處:287. 尋找重復數

難度

6 級

題目描述

要求

給定一個包含 n + 1 \texttt{n} + \texttt{1} n+1 個整數的數組 nums \texttt{nums} nums,每個整數都在范圍 [1, n] \texttt{[1, n]} [1,?n] 內(包括 1 \texttt{1} 1 n \texttt{n} n)。

數組 nums \texttt{nums} nums 只有一個重復的整數,返回這個重復的數。

要求不修改數組 nums \texttt{nums} nums 且只用常量級的額外空間。

示例

示例 1:

輸入: nums = [1,3,4,2,2] \texttt{nums = [1,3,4,2,2]} nums?=?[1,3,4,2,2]
輸出: 2 \texttt{2} 2

示例 2:

輸入: nums = [3,1,3,4,2] \texttt{nums = [3,1,3,4,2]} nums?=?[3,1,3,4,2]
輸出: 3 \texttt{3} 3

示例 3:

輸入: nums = [3,3,3,3,3] \texttt{nums = [3,3,3,3,3]} nums?=?[3,3,3,3,3]
輸出: 3 \texttt{3} 3

數據范圍

  • 1 ≤ n ≤ 10 5 \texttt{1} \le \texttt{n} \le \texttt{10}^\texttt{5} 1n105
  • nums.length = n + 1 \texttt{nums.length} = \texttt{n} + \texttt{1} nums.length=n+1
  • 1 ≤ nums[i] ≤ n \texttt{1} \le \texttt{nums[i]} \le \texttt{n} 1nums[i]n
  • nums \texttt{nums} nums 中的所有整數都只出現一次,除了一個整數出現兩次或多次

進階

  • 如何證明 nums \texttt{nums} nums 中至少存在一個重復的數字?
  • 你可以設計一個線性級時間復雜度的解決方案嗎?

前言

由于數組的長度是 n + 1 n + 1 n+1,且最多包含 n n n 個不同的整數。根據抽屜原理(或鴿籠原理)可知,將數組的 n + 1 n + 1 n+1 個位置分配到 n n n 個不同的整數,至少有兩個位置分配到同一個整數,即該整數在數組中重復。因此數組中至少存在一個重復的數字。

由于這道題要求不修改數組且空間復雜度是 O ( 1 ) O(1) O(1),因此排序、哈希表等解法都是不允許的,需要使用其他解法尋找重復的數字。

解法一

思路和算法

每個正整數的二進制表示中至少有一位是 1 1 1。對于二進制表示的每一位,分別考慮數組 nums \textit{nums} nums 中的所有整數在該位的 1 1 1 的次數 countArr \textit{countArr} countArr 和范圍 [ 1 , n ] [1, n] [1,n] 中的所有整數在該位的 1 1 1 的次數 countNum \textit{countNum} countNum。假設整數 x x x 在數組 nums \textit{nums} nums 中出現超過一次,則 x x x 的二進制表示的每個 1 1 1 所在的位都滿足 countArr > countNum \textit{countArr} > \textit{countNum} countArr>countNum。理由如下。

  • 如果 x x x 出現兩次,則范圍 [ 1 , n ] [1, n] [1,n] 中的所有整數都在數組 nums \textit{nums} nums 中出現,因此對于 x x x 中等于 1 1 1 的每一位都有 countArr > countNum \textit{countArr} > \textit{countNum} countArr>countNum

  • 如果 x x x 出現超過兩次,則范圍 [ 1 , n ] [1, n] [1,n] 中的部分整數不在數組 nums \textit{nums} nums 中出現,可以看成 x x x 替代了這部分整數。對于 x x x 中等于 1 1 1 的每一位,被替代的整數在相應位的值等于 0 0 0 1 1 1。替代之前有 countArr > countNum \textit{countArr} > \textit{countNum} countArr>countNum,替代之后同樣有 countArr > countNum \textit{countArr} > \textit{countNum} countArr>countNum

除了 x x x 的二進制表示的每個 1 1 1 所在的位以外,其余位都不滿足 countArr > countNum \textit{countArr} > \textit{countNum} countArr>countNum。因此上述結論的逆命題也成立:假設所有滿足 countArr > countNum \textit{countArr} > \textit{countNum} countArr>countNum 的位組成的整數是 x x x,則 x x x 在數組 nums \textit{nums} nums 中出現超過一次。

根據上述分析,可以使用位運算尋找重復數。首先找到 n n n 的二進制表示的最高有效位,即最高位 1 1 1 所在的位數,然后依次遍歷最低有效位到最高有效位,對于每一位計算 countArr \textit{countArr} countArr countNum \textit{countNum} countNum,如果 countArr > countNum \textit{countArr} > \textit{countNum} countArr>countNum 則將該位加到重復數中。遍歷結束之后即可得到重復數。

代碼

class Solution {public int findDuplicate(int[] nums) {int n = nums.length - 1;int highBit = 0;int temp = n;while (temp != 0) {highBit = temp & (-temp);temp -= highBit;}int duplicate = 0;for (int i = 1; i <= highBit; i <<= 1) {int countArr = 0, countNum = 0;for (int num : nums) {int bit = num & i;if (bit != 0) {countArr++;}}for (int j = 1; j <= n; j++) {int bit = j & i;if (bit != 0) {countNum++;}}if (countArr > countNum) {duplicate += i;}}return duplicate;}
}

復雜度分析

  • 時間復雜度: O ( n log ? n ) O(n \log n) O(nlogn),其中 n n n 是數組 nums \textit{nums} nums 的長度減 1 1 1。需要遍歷的二進制表示位數是 O ( log ? n ) O(\log n) O(logn),對于每一位都需要 O ( n ) O(n) O(n) 的時間計算該位在重復數中是否等于 1 1 1,時間復雜度是 O ( n log ? n ) O(n \log n) O(nlogn)

  • 空間復雜度: O ( 1 ) O(1) O(1)

解法二

思路和算法

假設有一個長度為 n + 1 n + 1 n+1 的數組 counts \textit{counts} counts,其中 counts [ i ] \textit{counts}[i] counts[i] 表示數組 nums \textit{nums} nums 中的不超過 i i i 的整數個數。以下用 x x x 表示重復數。

如果 x x x 出現兩次,則當 i < x i < x i<x counts [ i ] = i \textit{counts}[i] = i counts[i]=i,當 i ≥ x i \ge x ix counts [ i ] = i + 1 > i \textit{counts}[i] = i + 1 > i counts[i]=i+1>i

如果 x x x 出現超過兩次,則范圍 [ 1 , n ] [1, n] [1,n] 中的部分整數不在數組 nums \textit{nums} nums 中出現,可以看成 x x x 替代了這部分整數,假設只有一個整數被替代,用 j j j 表示被替代的整數,分別考慮 j < x j < x j<x j > x j > x j>x 的情況。

  • 如果 j < x j < x j<x,則對于 i < x i < x i<x,不超過 i i i 的整數個數不變或減少,因此 counts [ i ] ≤ i \textit{counts}[i] \le i counts[i]i,對于 i ≥ x i \ge x ix,不超過 i i i 的整數個數不變,因此 counts [ i ] > i \textit{counts}[i] > i counts[i]>i

  • 如果 j > x j > x j>x,則對于 i < x i < x i<x,不超過 i i i 的整數個數不變,因此 counts [ i ] = i \textit{counts}[i] = i counts[i]=i,對于 i ≥ x i \ge x ix,不超過 i i i 的整數個數不變或增加,因此 counts [ i ] > i \textit{counts}[i] > i counts[i]>i

因此當 i < x i < x i<x counts [ i ] ≤ i \textit{counts}[i] \le i counts[i]i,當 i ≥ x i \ge x ix counts [ i ] > i \textit{counts}[i] > i counts[i]>i。如果被替代的整數有多個,該結論仍成立。

重復數 x x x 是使得 counts [ x ] > x \textit{counts}[x] > x counts[x]>x 成立的最小整數 x x x,可以使用二分查找的方法尋找重復數。

low \textit{low} low high \textit{high} high 分別表示二分查找的下界和上界。由于 x x x 在范圍 [ 1 , n ] [1, n] [1,n] 中,因此初始時 low = 1 \textit{low} = 1 low=1 high = n \textit{high} = n high=n

每次查找時,取 mid \textit{mid} mid low \textit{low} low high \textit{high} high 的平均數向下取整,計算數組 nums \textit{nums} nums 中的不超過 mid \textit{mid} mid 的整數個數 counts [ mid ] \textit{counts}[\textit{mid}] counts[mid],執行如下操作。

  • 如果 counts [ mid ] ≤ mid \textit{counts}[\textit{mid}] \le \textit{mid} counts[mid]mid,則重復數 x x x 小于等于 mid \textit{mid} mid,因此在 [ low , mid ] [\textit{low}, \textit{mid}] [low,mid] 中繼續查找。

  • 如果 counts [ mid ] > mid \textit{counts}[\textit{mid}] > \textit{mid} counts[mid]>mid,則重復數 x x x 大于 mid \textit{mid} mid,因此在 [ mid + 1 , high ] [\textit{mid} + 1, \textit{high}] [mid+1,high] 中繼續查找。

low = high \textit{low} = \textit{high} low=high 時,查找結束,此時 low \textit{low} low 即為重復數 x x x

實現方面,并不需要顯性創建數組 counts \textit{counts} counts,而是可以在二分查找的過程中根據當前的 mid \textit{mid} mid 遍歷數組 nums \textit{nums} nums 計算不超過 mid \textit{mid} mid 的整數個數,因此空間復雜度是 O ( 1 ) O(1) O(1)

代碼

class Solution {public int findDuplicate(int[] nums) {int n = nums.length - 1;int low = 1, high = n;while (low < high) {int mid = low + (high - low) / 2;int count = 0;for (int num : nums) {if (num <= mid) {count++;}}if (count > mid) {high = mid;} else {low = mid + 1;}}return low;}
}

復雜度分析

  • 時間復雜度: O ( n log ? n ) O(n \log n) O(nlogn),其中 n n n 是數組 nums \textit{nums} nums 的長度減 1 1 1。需要執行 O ( log ? n ) O(\log n) O(logn) 次二分查找,每次二分查找需要 O ( n ) O(n) O(n) 的時間遍歷數組 nums \textit{nums} nums 計算不超過特定值的整數個數,時間復雜度是 O ( n log ? n ) O(n \log n) O(nlogn)

  • 空間復雜度: O ( 1 ) O(1) O(1)

解法三

思路和算法

將數組看成有向圖,范圍 [ 0 , n ] [0, n] [0,n] 中的每個整數是一個結點,對于 0 ≤ i ≤ n 0 \le i \le n 0in 的每個下標 i i i,存在一條從 i i i 指向 nums [ i ] \textit{nums}[i] nums[i] 的有向邊。對于重復數 x x x,存在至少兩條指向 x x x 的邊,因此有向圖中存在環。

這道題可以看成在有向圖中尋找環的入口,可以使用「環形鏈表 II」的快慢指針做法。以下只說明使用快慢指針尋找重復數的做法,正確性證明見「環形鏈表 II 的題解」。

尋找重復數分成兩步。

第一步是使用快慢指針遍歷有向圖尋找相遇點。

初始時,快指針和慢指針都位于整數 0 0 0。每次將快指針移動兩步,慢指針移動一步,在至少移動一次的情況下,當快指針和慢指針相遇時,相遇的位置為相遇點。

第二步是將兩個指針分別從起點和相遇點開始遍歷有向圖尋找重復數。

初始時,兩個指針分別位于整數 0 0 0 和相遇點。每次將兩個指針各移動一步,兩個指針相遇的整數即為重復數。

代碼

class Solution {public int findDuplicate(int[] nums) {int fast = 0, slow = 0;int meet = -1;while (meet < 0) {fast = nums[nums[fast]];slow = nums[slow];if (fast == slow) {meet = fast;}}int pointer1 = 0, pointer2 = meet;while (pointer1 != pointer2) {pointer1 = nums[pointer1];pointer2 = nums[pointer2];}return pointer1;}
}

復雜度分析

  • 時間復雜度: O ( n ) O(n) O(n),其中 n n n 是數組 nums \textit{nums} nums 的長度減 1 1 1。快慢指針的時間復雜度是 O ( n ) O(n) O(n)

  • 空間復雜度: O ( 1 ) O(1) O(1)

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

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

相關文章

Elasticsearch:沒有 “AG” 的 RAG?

作者&#xff1a;來自 Elastic Gustavo Llermaly 了解如何利用語義搜索和 ELSER 構建一個強大且視覺上吸引人的問答體驗&#xff0c;而無需使用 LLMs。 想要獲得 Elastic 認證&#xff1f;查看下一期 Elasticsearch Engineer 培訓的時間&#xff01; Elasticsearch 擁有眾多新…

linux下安裝ollama網不好怎么辦?

文章目錄 前言kkgithub下載腳本,而不是直接運行修改腳本修改權限還是不行?前言 今天想在linux上面更新一下ollama,于是去到官網: https://ollama.com/download/linux linux下安裝ollama還是挺簡單的: curl -fsSL https://ollama.com/install.sh | sh我也是特別嗨皮地就…

相機-IMU聯合標定:相機-IMU外參標定

文章目錄 ??簡介??標定工具kalibr??標定數據錄制??相機-IMU外參標定??簡介 在 VINS(視覺慣性導航系統) 中,相機-IMU外參標定 是確保多傳感器數據時空統一的核心環節,其作用可概括為以下關鍵點: 坐標系對齊(空間同步),外參誤差會導致視覺特征點投影與IMU預積…

基于 Java 的實現前端組裝查詢語句,后端直接執行查詢方案,涵蓋前端和后端的設計思路

1. 前端設計 前端負責根據用戶輸入或交互條件,動態生成查詢參數,并通過 HTTP 請求發送到后端。 前端邏輯: 提供用戶界面(如表單、篩選器等),讓用戶選擇查詢條件。將用戶選擇的條件組裝成 JSON 格式的查詢參數。發送 HTTP 請求(如 POST 或 GET)到后端。示例: 假設用…

[STM32] 4-2 USART與串口通信(2)

文章目錄 前言4-2 USART與串口通信(2)數據發送過程雙緩沖與連續發送數據發送過程中的問題 數據接收過程TXE標志位&#xff08;發送數據寄存器空&#xff09;TC標志位&#xff08;發送完成標志位&#xff09;單個數據的發送數據的連續發送 接收過程中遇到的問題問題描述&#xf…

Qt多線程TCP服務器實現指南

在Qt中實現多線程TCP服務器可以通過為每個客戶端連接分配獨立的線程來處理&#xff0c;以提高并發性能。以下是一個分步實現的示例&#xff1a; 1. 自定義工作線程類&#xff08;處理客戶端通信&#xff09; // workerthread.h #include <QObject> #include <QTcpSo…

詳細介紹Python-pandas-DataFrame全部 *功能* 函數

Python-pandas-DataFrame全部 功能 函數 提示&#xff1a;幫幫志會陸續更新非常多的IT技術知識&#xff0c;希望分享的內容對您有用。本章分享的是pandas的使用語法。前后每一小節的內容是存在的有&#xff1a;學習and理解的關聯性。【幫幫志系列文章】&#xff1a;每個知識點…

香港科技大學廣州|可持續能源與環境學域博士招生宣講會—四川大學專場

香港科技大學廣州&#xff5c;可持續能源與環境學域博士招生宣講會—四川大學專場 時間&#xff1a;2025年5月8日&#xff08;星期四&#xff09;16:30開始 地點&#xff1a;四川大學基礎教學樓A座504 宣講嘉賓&#xff1a;肖殿勛 助理教授 一經錄取&#xff0c;享全額獎學金…

裝飾器設計模式(Decorator Pattern)詳解

裝飾器設計模式(Decorator Pattern)詳解 裝飾器模式是一種結構型設計模式,它允許動態地向對象添加額外行為,而無需修改其原始類。這種模式通過包裝對象的方式提供靈活的擴展功能替代繼承。 1. 核心概念 (1)模式定義 裝飾器模式:動態地給一個對象添加一些額外的職責,就…

【SpringMVC】詳解參數傳遞與實戰指南

目錄 1.前言 2.正文 2.1基礎參數傳遞 2.1.1單參數 2.1.2多參數 2.2對象參數綁定 2.2.1自動封裝對象 2.2.2參數別名處理 2.3集合類型處理 2.3.1數組接收 2.3.2List集合接收 2.4JSON參數處理 2.4.1介紹JSON 2.4.2傳遞JSON參數 2.5RESTful風格參數 2.6文件上傳處理…

mysql-窗口函數一

目錄 一、感受一下分組與窗口函數的區別 二、滑動窗口&#xff08;子窗口&#xff09;大小的確認 2.1 分組函數下order by使用 2.2 窗口子句 2.3 執行流程 三、函數使用 窗口函數需要mysql的版本大于等于8才行&#xff0c;可以先檢查一下自己的mysql版本是多少 select ve…

解決在Mac上無法使用“ll”命令

在 macOS 上&#xff0c;ll 命令是一個常見的別名&#xff0c;它通常是指向 ls -l 的。但是&#xff0c;如果你看到 zsh: command not found: ll&#xff0c;這意味著你當前的 zsh 配置中沒有設置 ll 作為別名。 解決方法&#xff1a; 1. 使用 ls -l 命令 如果只是想查看目錄…

GTA5(傳承/增強) 13980+真車 超跑 大型載具MOD整合包+最新GTA6大型地圖MOD 5月最新更新

1500超跑載具 1000普通超跑 1500真車超跑 各種軍載具1000 各種普通跑車 船舶 飛機 1000 人物1500 添加式led載具1000 超級英雄最新版 添加添加式武器MOD1000 添加地圖MOD500 添加超跑載具2000 當前共計1.2wMOD 4月2日更新 新增770menyoo地圖 當前共計12770 新增48款超級英雄最新…

初學Vue之記事本案例

初學Vue之記事本案例 案例功能需求相關Vue知識案例實現1.實現方法及代碼2.演示 案例收獲與總結 案例功能需求 基于Vue實現記事功能&#xff08;不通過原生JS實現&#xff09; 1.點擊保存按鈕將文本框的內容顯示在特定位置&#xff0c;且清空文本框內容 2.點擊清空按鈕&#x…

一個linux系統電腦,一個windows電腦,怎么實現某一個文件夾共享

下載Samba linux主機名字不能超過15個字符 sudo dnf install samba samba-client -y 創建共享文件夾 sudo mkdir /shared 配置文件 vim /etc/samba/smb.conf [shared] path /shared available yes valid users linux電腦用戶 read only no browsable yes p…

樹莓派5+edge-tts 語音合成并進行播放測試

簡介 Edge-TTS 是一個基于微軟 Edge 瀏覽器的開源文本轉語音(TTS)工具,主要用于將文本轉換為自然流暢的語音。它利用了微軟 Azure 的 TTS 技術,支持多種語言和聲音,同時具備高質量的語音合成能力。這里簡單演示在樹莓派中安裝該項目進行簡單測試。 開源倉庫地址:https:/…

多模態革命!拆解夸克AI相機技術架構:如何用視覺搜索重構信息交互?(附開源方案對比)

一、技術人必看&#xff1a;視覺搜索背后的多模態架構設計 夸克「拍照問夸克」功能絕非簡單的OCRQA拼接&#xff0c;而是一套多模態感知-推理-生成全鏈路系統&#xff0c;其技術棧值得開發者深挖&#xff1a; 視覺編碼器&#xff1a;基于Swin Transformer V2&#xff0c;支持4…

論文閱讀:2024 ICLR Workshop. A STRONGREJECT for Empty Jailbreaks

總目錄 大模型安全相關研究&#xff1a;https://blog.csdn.net/WhiffeYF/article/details/142132328 A STRONGREJECT for Empty Jailbreaks 對空越獄的 StrongREJECT https://arxiv.org/pdf/2402.10260 https://github.com/dsbowen/strong_reject https://strong-reject.re…

AI生成Flutter UI代碼實踐(一)

之前的雜談中有提到目前的一些主流AI編程工具&#xff0c;比如Cursor&#xff0c;Copilot&#xff0c;Trea等。因為我是Android 開發&#xff0c;日常使用Android Studio&#xff0c;所以日常使用最多的還是Copilot&#xff0c;畢竟Github月月送我會員&#xff0c;白嫖還是挺香…

計網分層體系結構(包括OSI,IP,兩者對比和相關概念)

眾所周知&#xff0c;就像我們計算機領域中的任何東西一樣&#xff0c;計算機網絡也是個分層的體系結構&#xff0c;現代提出的結構就兩種——OSI和TCP/IP&#xff0c;我們先來剖析并對比一下這兩種模型&#xff0c;然后總結一下分層思想中的一些共性。 TCP/IP與OSI結構對比圖 …