【算法】摩爾投票算法

目錄

  • 1.概述
  • 2.算法思想
  • 3.代碼實現
    • 3.1.t = ?n / 2?
    • 3.2.t = ?n / 3?
    • 3.3.t = ?n / (m + 1)?
  • 4.應用

參考:LeetCode_多數元素 II 題解

1.概述

(1)摩爾投票法 (Boyer–Moore Majority Vote Algorithm) 是一種用來尋找一組元素中多數元素的常量級空間復雜度算法。一般來說,摩爾投票法常用于求眾數,求眾數這個問題本身比較簡單,但是想要使用常量級空間復雜度來實現卻不是那么簡單。而摩爾投票法正是這樣一種算法。

(2)眾數 (Mode) 是指在統計分布上具有明顯集中趨勢點的數值,代表數據的一般水平。 也是一組數據中出現次數最多的數值,有時眾數在一組數中有好幾個。用 M 表示。上面提到的多數元素與眾數的含義差不多,只不過在摩爾投票法算法中,多數元素是指在數組(長度為 n)中出現次數大于某個閾值 (t) 的元素,并且存在如下結論:

  • 如果 t = ?n / 2?,那么多數元素最多只有 1 個;
  • 如果 t = ?n / 3?,那么多數元素最多只有 2 個;
  • 如果 t = ?n / (m + 1)?,那么多數元素最多只有 m 個;

2.算法思想

(1)摩爾投票法的核心思想為對拼消耗。首先我們考慮最基本的摩爾投票問題,比如找出一組數字序列中出現次數大于 ?n / 2? 的數字(并且假設這個數字一定存在)。我們可以直接利用反證法證明這樣的數字只可能有一個:

  • 假設我們當前數組中存在次數大于總數一半的元素為 x,數組的總長度為 n,則我們可以把數組分為兩部分:
    • 一部分為相同的 k 個元素 x;
    • 另一部分為 n ? k 2 \frac{n - k}{2} 2n?k? 對個不同的元素配對,
  • 此時我們假設還存在另外一個次數大于總數一半的元素 y,則此時 y 因該滿足 y > n 2 \frac{n}{2} 2n? ,但是按照我們之前的推理 y 應當滿足 y ≤ n ? k 2 \frac{n - k}{2} 2n?k? ,二者自相矛盾。

因此,對于 t = ?n / 2?,摩爾投票算法的核心思想是基于這個事實:每次從序列里選擇兩個不相同的數字刪除掉(或稱為抵消),最后剩下一個數字或幾個相同的數字,就是出現次數大于總數一半的那個元素。

(2)對于 t = ?n / 3?,我們可以利用反證法推斷出滿足這樣條件的元素最多只有兩個,同理,我們可以利用摩爾投票法的核心思想,每次選擇三個互不相同的元素進行刪除(或稱為「抵消」),推導思路如下:

  • 假設數組中一定只存在一個次數大于 ? n 3 \frac{n}{3} 3n?? 的元素 x,則此時我們可以把數組分成兩部分:一部分相同的 k 個元素 x,另一部分為 n ? k 3 \frac{n - k}{3} 3n?k? 組三個不同的元素,我們知道三個不同的元素會被抵消,因此最終只會剩下一個元素為 x。
  • 如果只存在 2 個次數大于 ? n 3 \frac{n}{3} 3n?? 的元素時,假設這兩個不同的元素分別為 x 和 y,則此時我們一定可以把數組分成三部分:第一部分相同的 m 個元素 x,第二部分相同的 k 個元素 y,第三部分為 n ? m ? k 3 \frac{n - m - k}{3} 3n?m?k? 組三個互不同的元素,我們知道三個互不同的元素會被抵消,因此最終只會剩下兩個元素為 x 和 y。

具體思路如下:

  • 我們每次檢測當前元素是否為第一個選中的元素或者第二個選中的元素;
  • 每次我們發現當前元素與已經選中的兩個元素都不相同,則進行抵消一次;
  • 如果存在最終選票大于 0 的元素,我們還需要再次統計已選中元素的次數,檢查元素的次數是否大于 ? n 3 \frac{n}{3} 3n??。

(3)對于 t = ?n / (m + 1)?,我們可以利用同樣的方法推斷出滿足這樣條件的元素最多只有 m 個。但是需要注意的是,此時算法時間復雜度為 O(n * m),空間復雜度為 O(m)

3.代碼實現

3.1.t = ?n / 2?

class Solution {public int majorityElement(int[] nums) {//設 candidate 為出現次數大于 ?n / 2? 的元素int candidate = 0;int cnt = 0;//遍歷數組 numsfor (int num : nums) {if (cnt == 0) {//重新確定選舉人candidate = num;}if (num == candidate) {//candidate 的票數加一cnt++;} else {//對拼消耗,即相當于 candidate 的票數減一cnt--;}}return candidate;}
}

① 上述算法的時間復雜度為 O(n),空間復雜度為 O(1)。
② 有關 t = ?n / 2? 的摩爾投票算法的具體細節,可以參考本題官方題解。

3.2.t = ?n / 3?

class Solution {public List<Integer> majorityElement(int[] nums) {//滿足題目條件的元素最多只有兩個,我們設為 ele1 和 ele2int ele1 = 0;int ele2 = 0;//設 vote1 和 vote2 分別為 ele1 和 ele2 的贊成票數int vote1 = 0;int vote2 = 0;for (int num : nums) {if (vote1 > 0 && num == ele1) {//num 為第一個元素,則票數加 1vote1++;} else if (vote2 > 0 && num == ele2) {//num 為第二個元素,則票數加 1vote2++;} else if (vote1 == 0) {//選擇第一個元素ele1 = num;vote1++;} else if (vote2 == 0) {//選擇第二個元素ele2 = num;vote2++;} else {//三個元素 ele1、ele3、num 互不相同,則其票數減 1,即對拼消耗vote1--;vote2--;}}//cnt1 和 cnt2 分別記錄元素 ele1 和 ele2 出現的次數int cnt1 = 0;int cnt2 = 0;for (int num : nums) {if (vote1 > 0 && num == ele1) {cnt1++;}if (vote2 > 0 && num == ele2) {cnt2++;}}//檢查元素出現的次數是否滿足要求List<Integer> res = new ArrayList<>();if (vote1 > 0 && cnt1 > nums.length / 3) {res.add(ele1);} if (vote2 > 0 && cnt2 > nums.length / 3) {res.add(ele2);}return res;}
}

上述算法的時間復雜度為 O(n),空間復雜度為 O(1)。

3.3.t = ?n / (m + 1)?

class Solution {public static List<Integer> majorityElements(int[] nums, int m) {//存儲多數元素的集合List<Integer> res = new ArrayList<>();//候選元素數組int[] candidates = new int[m];//對應候選元素的計數器數組int[] counts = new int[m];for (int num : nums) {//如果 num 存在于候選元素數組中,則將對應計數器加 1for (int i = 0; i < m; i++) {if (candidates[i] == num) {counts[i]++;break;}//如果 num 不在候選元素數組中且有空位置(計數器為 0),則將 num 加入候選元素數組if (candidates[i] == 0 && counts[i] == 0) {candidates[i] = num;counts[i]++;break;}}//如果候選元素數組已滿,則將所有計數器減 1if (counts[m - 1] != 0) {for (int i = 0; i < m; i++) {counts[i]--;}}}//驗證候選元素的計數器是否大于閾值for (int i = 0; i < m; i++) {int count = 0;for (int num : nums) {if (num == candidates[i]) {count++;}}if (count > nums.length / (m + 1)) {res.add(candidates[i]);}}return res;}
}

4.應用

大家可以去 LeetCode 上找相關的 Boyer-Moore 投票算法的題目來練習,或者也可以直接查看 LeetCode 算法刷題目錄 (Java) 這篇文章中的 Boyer-Moore 投票算法章節。如果大家發現文章中的錯誤之處,可在評論區中指出。

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

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

相關文章

flutter,uni-app開發調試ios

一、申請ios開發者賬號 二、ios開發者配置 ios 開發者需要配置的地方 https://developer.apple.com/account/resources/certificates/list Certificates&#xff08;證書&#xff09;: 作用&#xff1a; 證書用于對應用程序和開發者進行身份驗證&#xff0c;確保安全性和可…

如何為您的企業選擇合適的多因素認證?

在傳統的網絡安全架構中&#xff0c;重點在于防止非法入侵&#xff0c;例如防火墻、VPN 、堡壘機等安全設備的重心都在于防止用戶違規訪問企業資源&#xff0c;一旦合法用戶的賬號密碼被入侵者拿到&#xff0c;就可以冒充合法用戶訪問企業資源&#xff0c;所有的安全設備形同虛…

springcloud超市管理系統源碼

技術說明&#xff1a; jdk1.8&#xff0c;mysql5.7&#xff0c;idea&#xff0c;vscode springcloud springboot mybatis vue elementui mysql 功能介紹&#xff1a; 后臺管理&#xff1a; 統計分析&#xff1a;查看用戶&#xff0c;商品&#xff0c;銷售數量&#xff1b;…

Mock 數據

1. Mock 數據的方式 2. json-server 實現 Mock 數據 項目中安裝json-server npm i -D json-server準備一個json文件添加啟動命令 //package.json"scripts": {"start": "craco start","build": "craco build","test&q…

簡單聊聊加密和加簽的關系與區別

大家好&#xff0c;我是G探險者。 平時我們在項目上一定都聽過加密和加簽&#xff0c;加密可能都好理解&#xff0c;知道它是保障的數據的機密性&#xff0c;那加簽是為了保障啥勒&#xff1f;它和加密有啥區別&#xff1f; 帶著這個疑問&#xff0c;我們就來聊聊二者的區別。…

SHEIN出口車鑰匙扣REACH認證指南解析

鑰匙扣的材料一般為金屬、皮革、塑料、橡膠、木頭等。此物精致小巧、造型千變萬化是人們隨身攜帶的日常用品。鑰匙扣是掛在鑰匙圈上的一種裝飾物品。鑰匙扣出口需要辦理REACH認證。 一、什么是REACH認證&#xff1f; REACH認證是歐盟28個成員國對進入其市場的所有化學品,&…

centos7中通過minikube安裝Kubernetes

minikube是一款開源的Kubernetes集群管理器&#xff0c;它可以幫助您在本地計算機上輕松部署和管理Kubernetes集群。以下是minikube的安裝和使用步驟&#xff1a; 安裝Docker&#xff1a;如果您還沒有安裝Docker&#xff0c;可以從Docker官方網站上下載并安裝適合您操作系統的…

Android和iOS應用程序加固方法詳解:混淆、加殼、數據加密、動態加載和數字簽名實現

目錄 Android和iOS應用程序加固方法詳解&#xff1a;混淆、加殼、數據加密、動態加載和數字簽名實現 APP 加固方式 iOS APP加固代碼實現 打開要處理的IPA文件 設置簽名使用的證書和描述文件 開始ios ipa重簽名 APP 加固方式 iOSAPP 加固是優化 iOS安全性的一種方法&…

C#枚舉的使用

在C#中經常會用到枚舉&#xff0c;是比較常用的定義一組常量集合的數據類型。我們使用枚舉可以更方便理解和閱讀代碼&#xff0c;增強代碼可讀性&#xff0c;也在某種程度上提升了編程邏輯和維度。 基本語法&#xff1a; enum MyEnum {Value1,Value2,Value3&#xff0c;//...…

CSS 實現文本框簽名

<div class"textarea-prepend"><textarea rows"6" placeholder"請輸入消息內容"></textarea></div>.textarea-prepend {position: relative;}.textarea-prepend textarea {width: 300px;}.textarea-prepend::before {ba…

UE4基礎篇十三:物理

一、筆記記錄 1.1 碰撞交互 阻擋會設置為阻擋的兩個(或更多)Actor之間自然發生。但是,需要啟用模擬生成命中事件(Simulation Generates Hit Events)才能執行事件命中 ,要兩個都相互設置阻擋模式才會生成命中事件 將Actor設置為重疊往往看起來它們彼此忽略,如果沒有生…

【陳老板贈書活動 - 18期】-如何成為架構師這幾本書推薦給你

陳老老老板&#x1f9b8; &#x1f468;?&#x1f4bb;本文專欄&#xff1a;贈書活動專欄&#xff08;為大家爭取的福利&#xff0c;免費送書&#xff09; &#x1f468;?&#x1f4bb;本文簡述&#xff1a;生活就像海洋,只有意志堅強的人,才能到達彼岸。 &#x1f468;?&am…

JavaScript基礎—引入方式、注釋和結束符、輸入和輸出、變量、常量、數據類型、檢測數據類型、類型轉換、綜合案例—用戶訂單信息

版本說明 當前版本號[20231123]。 版本修改說明20231123初版 目錄 文章目錄 版本說明目錄JavaScript 基礎 - 第1天介紹引入方式內部方式外部形式 注釋和結束符單行注釋多行注釋 結束符輸入和輸出輸出輸入 變量聲明賦值變量初始化更新變量 關鍵字變量名命名規則 常量數據類型…

什么是指針碰撞

程序員的公眾號&#xff1a;源1024&#xff0c;獲取更多資料&#xff0c;無加密無套路&#xff01; 最近整理了一波電子書籍資料&#xff0c;包含《Effective Java中文版 第2版》《深入JAVA虛擬機》&#xff0c;《重構改善既有代碼設計》&#xff0c;《MySQL高性能-第3版》&…

WorkPlus實現完全私有化部署,企業數據安全有保障

在這個信息化飛速發展的時代&#xff0c;企業正面臨著越來越多的數據安全挑戰。為了確保數據的安全性和隱私性&#xff0c;WorkPlus迎合市場需求&#xff0c;推出了完全私有化部署方案&#xff0c;為企業提供了全面、可靠的安全保障&#xff0c;成為企業移動辦公的首選。 WorkP…

C#中的迭代器和分部類

目錄 一、迭代器 1.示例源碼 2.生成效果&#xff1a; 二、分部類 1.示例源碼 2.生成效果 迭代器在集合類中經常使用&#xff0c;而分部類則提供了一種將一個類分成多個類的方法&#xff0c;這對于有大量代碼的類非常實用。 一、迭代器 迭代器是可以返回相同類型的值的有…

LeetCode216. Combination Sum III

文章目錄 一、題目二、題解 一、題目 Find all valid combinations of k numbers that sum up to n such that the following conditions are true: Only numbers 1 through 9 are used. Each number is used at most once. Return a list of all possible valid combination…

《微信小程序開發從入門到實戰》學習二十五

3.3 開發創建投票頁面 3.3.13 使用頁面路徑參數 寫了很多重復代碼&#xff0c;現在想辦法將多選和單選投票頁面合二為一。 將單選頁面改造作為單選多選共同頁面。 修改index.js中的代碼&#xff0c;將路徑都跳轉到第一個單選頁面&#xff0c;帶上單選或多選的標志&#xff…

阿里云 E-MapReduce 全面開啟 Serverless 時代

作者&#xff1a;李鈺 - 阿里云資深技術專家、EMR 負責人 EMR 2.0 平臺 阿里云正式發布云原生開源大數據平臺EMR 2.0已歷經一年時間&#xff0c;如今EMR 2.0全新平臺在生產上已經全面落地&#xff0c;資源占比超過60%。EMR 2.0平臺之所以在生產上這么快落地&#xff0c;源于其…

EPT-Net:用于3D醫學圖像分割的邊緣感知轉換器

EPT-Net: Edge Perception Transformer for 3D Medical Image Segmentation EPT-Net&#xff1a;用于3D醫學圖像分割的邊緣感知轉換器背景貢獻實驗方法Dual Positional Transformer&#xff08;雙位置Transformer&#xff09;Learnable Patch EmbeddingVoxel Spacial Positiona…