Leetcode 07 java

169. 多數元素

給定一個大小為?n?的數組?nums?,返回其中的多數元素。

多數元素是指在數組中出現次數?大于?? n/2 ??的元素。

你可以假設數組是非空的,并且給定的數組總是存在多數元素。

示例?1:

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

示例?2:

輸入:nums = [2,2,1,1,1,2,2]
輸出:2

提示:

  • n == nums.length
  • 1 <= n <= 5 * 104
  • -109 <= nums[i] <= 109

進階:嘗試設計時間復雜度為 O(n)、空間復雜度為 O(1) 的算法解決此問題。

我的想法:

之前一眼hash的時候用的是異或,這個題目不是簡單的計數,所以大概hash也是可行的吧,嗯...異或只能判斷出現的奇偶性。

1 分析一下異或,hash的解法可行性

你的想法嘗試使用哈希或異或操作來解決問題,不過這兩種方法在這個問題上有一些限制:

1.?異或操作的局限性

你提到 "異或只能判斷出現的奇偶性",這是正確的。異或(XOR)的性質是:

  • 相同元素異或結果為 0(如?a ^ a = 0
  • 任何元素與 0 異或結果為自身(如?a ^ 0 = a

因此,如果一個元素出現奇數次,異或結果會保留該元素;但如果出現偶數次,異或結果會抵消為 0。然而,這個問題要求的是 " 出現次數大于 n/2" 的元素,而異或無法直接統計次數或比較頻率,所以異或在這里不適用。

2.?哈希表的正確用法

雖然你提到 "hash 也是可行的吧",但需要注意哈希表的具體用法:

  • 錯誤用法:若用哈希表存儲元素的異或結果,無法解決問題(與直接異或數組相同)。
  • 正確用法:用哈希表統計每個元素的出現次數,然后遍歷哈希表找到次數超過 n/2 的元素。

例如:

java

運行

import java.util.HashMap;
import java.util.Map;class Solution {public int majorityElement(int[] nums) {Map<Integer, Integer> countMap = new HashMap<>();for (int num : nums) {countMap.put(num, countMap.getOrDefault(num, 0) + 1);}for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {if (entry.getValue() > nums.length / 2) {return entry.getKey();}}return -1; // 題目保證存在多數元素,不會執行到這里}
}

這個方法的時間和空間復雜度都是 O (n),符合題目要求,但不是最優解。

3.?最優解法:摩爾投票法(Boyer-Moore Voting Algorithm)

如果追求 O (1) 空間復雜度,可以使用摩爾投票法:

java

運行

class Solution {public int majorityElement(int[] nums) {int count = 0;Integer candidate = null;for (int num : nums) {if (count == 0) {candidate = num;}count += (num == candidate) ? 1 : -1;}return candidate;}
}

原理

  • 遍歷數組時維護一個候選元素?candidate?和計數器?count
  • 遇到與?candidate?相同的元素,count +1;否則?count -1
  • 當?count?減為 0 時,更換候選元素為當前元素。
  • 由于多數元素出現次數超過一半,最終候選元素一定是多數元素。

總結

你的方向(哈希或異或)有一定合理性,但需要注意:

  • 異或無法直接解決該問題,因為它不統計次數,只判斷奇偶性。
  • 哈希表需要用于統計次數,而不是異或操作。
  • 摩爾投票法是最優解,滿足 O (n) 時間和 O (1) 空間。

2 hash表解法

import java.util.HashMap;
import java.util.Map;class Solution {public int majorityElement(int[] nums) {// 1. 創建一個哈希表,鍵為數組中的元素,值為該元素出現的次數Map<Integer, Integer> countMap = new HashMap<>();// 2. 遍歷數組中的每個元素for (int num : nums) {// 3. 對于當前元素num,獲取它在哈希表中已有的計數//    getOrDefault方法:如果num存在,返回其計數;否則返回默認值0int currentCount = countMap.getOrDefault(num, 0);// 4. 將當前元素的計數加1,并更新到哈希表中//    put方法:將鍵值對 (num, currentCount + 1) 存入哈希表//    如果鍵num已存在,會覆蓋舊值;如果不存在,則創建新的鍵值對countMap.put(num, currentCount + 1);}// 5. 遍歷哈希表,找出出現次數超過數組長度一半的元素for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {// entry.getKey() 返回當前鍵(元素值)// entry.getValue() 返回當前值(出現次數)if (entry.getValue() > nums.length / 2) {return entry.getKey();}}// 根據題目假設,數組中總是存在多數元素,因此不會執行到這里return -1;}
}

關于put方法的詳細解釋

put是 HashMap 類的核心方法,用于存儲或更新鍵值對:

java

運行

map.put(key, value);
  • 功能

    • 如果key不存在于哈希表中:創建新的鍵值對(key, value)
    • 如果key已存在:用新的value覆蓋舊值(舊值會被丟棄)。
  • 示例

    java

    運行

    Map<String, Integer> scores = new HashMap<>();
    scores.put("Alice", 90);    // 添加新鍵值對:Alice -> 90
    scores.put("Bob", 85);      // 添加新鍵值對:Bob -> 85
    scores.put("Alice", 95);    // 更新已有鍵:Alice -> 95(舊值90被覆蓋)
    
  • 在本題中的作用

    java

    運行

    countMap.put(num, currentCount + 1);
    
    ?

    這行代碼會將元素num的計數更新為currentCount + 1,無論num之前是否存在于哈希表中。

復雜度分析

  • 時間復雜度:O (n) —— 遍歷數組一次,遍歷哈希表一次。
  • 空間復雜度:O (n) —— 最壞情況下,哈希表需要存儲所有元素。

getOrDefault?是 Java 中?Map?接口提供的一個實用方法,用于安全地獲取鍵對應的值,避免?NullPointerException。我來詳細解釋它的用法和在這個問題中的作用。

getOrDefault?方法詳解

方法簽名

java

運行

V getOrDefault(Object key, V defaultValue);
  • 參數
    • key:要查找的鍵。
    • defaultValue:如果鍵不存在時返回的默認值。
  • 返回值
    • 如果鍵存在,返回對應的值;
    • 如果鍵不存在,返回?defaultValue

為什么需要?getOrDefault

在統計元素次數時,傳統寫法需要先檢查鍵是否存在,不存在則初始化為 0,存在則加 1:

java

運行

// 傳統寫法(不使用 getOrDefault)
if (countMap.containsKey(num)) {// 鍵存在,取出舊值并加 1int oldCount = countMap.get(num);countMap.put(num, oldCount + 1);
} else {// 鍵不存在,初始化為 1countMap.put(num, 1);
}

使用?getOrDefault?可以簡化這個邏輯,一行代碼完成統計

java

運行

// 等效寫法(使用 getOrDefault)
int currentCount = countMap.getOrDefault(num, 0); // 不存在則默認 0
countMap.put(num, currentCount + 1); // 直接更新計數

在多數元素問題中的應用

讓我結合原題代碼,逐行解釋?getOrDefault?的作用:

java

運行

import java.util.HashMap;
import java.util.Map;class Solution {public int majorityElement(int[] nums) {Map<Integer, Integer> countMap = new HashMap<>();for (int num : nums) {// 1. 獲取當前元素 num 的已有計數//    如果 num 第一次出現,getOrDefault 返回默認值 0//    如果 num 已存在,返回其當前計數int currentCount = countMap.getOrDefault(num, 0);// 2. 將計數加 1 后存入哈希表//    如果 num 是第一次出現,這行代碼會創建新的鍵值對 (num, 1)//    如果 num 已存在,這行代碼會覆蓋舊值,更新為新的計數countMap.put(num, currentCount + 1);}// ...后續代碼不變...}
}

對比實驗:理解?getOrDefault?的行為

假設我們有一個空的哈希表?countMap,執行以下操作:

java

運行

Map<Integer, Integer> countMap = new HashMap<>();// 第一次遇到元素 3
int count1 = countMap.getOrDefault(3, 0); // 返回 0(鍵不存在)
countMap.put(3, count1 + 1); // 存入 (3, 1)// 第二次遇到元素 3
int count2 = countMap.getOrDefault(3, 0); // 返回 1(鍵已存在)
countMap.put(3, count2 + 1); // 存入 (3, 2)// 最終哈希表中:{3=2}

其他常見用法場景

  1. 統計字符串中字符出現次數

    java

    運行

    String s = "hello";
    Map<Character, Integer> charCount = new HashMap<>();
    for (char c : s.toCharArray()) {charCount.put(c, charCount.getOrDefault(c, 0) + 1);
    }
    // 結果:{h=1, e=1, l=2, o=1}
    
  2. 分組統計

    java

    運行

    List<String> words = Arrays.asList("apple", "banana", "apple");
    Map<Integer, Integer> lengthCount = new HashMap<>();
    for (String word : words) {int length = word.length();lengthCount.put(length, lengthCount.getOrDefault(length, 0) + 1);
    }
    // 結果:{5=1, 6=2}(長度為5的單詞1個,長度為6的單詞2個)
    

總結

getOrDefault?是處理哈希表計數問題的 “語法糖”,它的核心優勢是:

  • 簡化代碼:避免了手動檢查鍵是否存在的繁瑣邏輯。
  • 防止空指針異常:當鍵不存在時返回默認值(如 0),而不是?null
  • 代碼可讀性:讓統計邏輯更加清晰直觀。

處理需要初始化默認值的場景時,它是 Java 程序員的常用工具之一!

3?摩爾投票法(Boyer-Moore Voting Algorithm)

摩爾投票法(Boyer-Moore Voting Algorithm),這個算法的核心思想可以用一句話概括:"多數元素在數組中出現的次數超過一半,因此即使與其他所有元素兩兩抵消,最終也會剩下至少一個自身"

class Solution {public int majorityElement(int[] nums) {// 初始化計數器,用于記錄當前候選人的票數int count = 0;// 初始化候選人,Integer類型允許為null,表示尚未選出候選人Integer candidate = null;// 遍歷數組中的每個元素for (int num : nums) {// 當計數器為0時,意味著當前候選人的票數已被完全抵消// 需要選擇當前元素作為新的候選人if (count == 0) {candidate = num;}// 根據當前元素是否等于候選人來更新計數器:// - 如果相等,說明遇到了支持者,票數+1// - 如果不等,說明遇到了反對者,票數-1count += (num == candidate) ? 1 : -1;}// 遍歷結束后,最終的候選人即為多數元素// 由于多數元素的數量超過n/2,即使中途被抵消,最終也會勝出return candidate;}
}

核心邏輯解釋

  1. 候選人交替

    • count減為 0 時,說明當前候選人的支持票被反對票完全抵消,此時需要更換候選人為當前元素。
  2. 票數更新

    • 遇到與候選人相同的元素時,count增加 1(支持票)
    • 遇到與候選人不同的元素時,count減少 1(反對票)
  3. 最終勝利條件

    • 由于多數元素的出現次數超過一半,即使在遍歷過程中被其他元素抵消,最終也會因為自身數量優勢重新成為候選人并保持到最后。

算法核心思想

想象一場投票選舉,每個候選人需要和對手 "一對一拼消耗":

  • 每次遇到自己的支持者,票數?+1
  • 每次遇到對手,票數?-1
  • 當票數減為?0?時,當前候選人 "下臺",由新的候選人接替。

由于多數元素的支持者超過半數,即使其他所有候選人聯合起來抵消票數,多數元素最終仍會勝出。

算法步驟拆解

我們用數組?[2, 2, 1, 1, 1, 2, 2]?為例,逐步演示算法過程:

  1. 初始化

    • candidate(當前候選人):null
    • count(當前票數):0
  2. 遍歷數組

    • 第 1 個元素?2

      • 當前?count = 0,任命?2?為新候選人,count +1?→?1
      • 狀態:candidate = 2,?count = 1
    • 第 2 個元素?2

      • 與候選人相同,count +1?→?2
      • 狀態:candidate = 2,?count = 2
    • 第 3 個元素?1

      • 與候選人不同,count -1?→?1
      • 狀態:candidate = 2,?count = 1
    • 第 4 個元素?1

      • 與候選人不同,count -1?→?0
      • 狀態:candidate = 2,?count = 0(候選人下臺)。
    • 第 5 個元素?1

      • 當前?count = 0,任命?1?為新候選人,count +1?→?1
      • 狀態:candidate = 1,?count = 1
    • 第 6 個元素?2

      • 與候選人不同,count -1?→?0
      • 狀態:candidate = 1,?count = 0(候選人下臺)。
    • 第 7 個元素?2

      • 當前?count = 0,任命?2?為新候選人,count +1?→?1
      • 狀態:candidate = 2,?count = 1
  3. 遍歷結束:最終候選人是?2,返回?2

代碼實現(Java)

java

運行

class Solution {public int majorityElement(int[] nums) {int count = 0;        // 記錄當前候選人的票數Integer candidate = null;  // 當前候選人(初始為 null)for (int num : nums) {// 當票數為 0 時,更換候選人if (count == 0) {candidate = num;}// 根據當前元素是否等于候選人,更新票數count += (num == candidate) ? 1 : -1;}return candidate;  // 最終剩下的候選人即為多數元素}
}

關鍵細節解釋

  1. 為什么?count = 0?時更換候選人?

    • 當?count = 0?時,說明當前候選人的票數已被完全抵消,需要重新選擇候選人。
    • 由于多數元素的數量超過一半,即使中途被其他元素抵消,最終仍會重新成為候選人并勝出。
  2. 為什么不需要驗證最終候選人?

    • 根據算法邏輯,多數元素的數量超過?n/2,因此無論其他元素如何抵消,多數元素最終的票數至少為?1
    • 因此,最后剩下的候選人必然是多數元素。

復雜度分析

  • 時間復雜度:O (n) —— 只需遍歷一次數組。
  • 空間復雜度:O (1) —— 只需要常數級的額外空間。

進階思考:如果沒有多數元素會怎樣?

如果數組中不存在多數元素,摩爾投票法會返回一個錯誤的結果。例如:

  • 數組?[1, 2, 3]:最終返回?3,但?3?并不是多數元素。

因此,如果題目沒有明確保證存在多數元素,需要在算法結束后額外驗證最終候選人是否真的超過半數:

java

運行

// 增加驗證步驟
int candidate = majorityElement(nums);  // 調用摩爾投票法
int count = 0;
for (int num : nums) {if (num == candidate) count++;
}
if (count > nums.length / 2) {return candidate;
} else {return -1;  // 不存在多數元素
}

總結

摩爾投票法的美在于:

  • 無需額外空間:通過巧妙的抵消策略,直接在遍歷中找出多數元素。
  • 線性時間復雜度:一次遍歷即可完成,效率極高。
  • 思想深刻:將問題轉化為 "投票抵消" 模型,直觀且優雅。

這個算法在處理大規模數據時尤為高效,是面試中的高頻考點,建議反復理解其核心思想!

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

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

相關文章

CS231n-2017 Lecture6訓練神經網絡(一)筆記

本節主要講的是模型訓練時的算法設計數據預處理&#xff1a;關于數據預處理&#xff0c;我們有常用的3個符號&#xff0c;數據矩陣X&#xff0c;假設其尺寸是&#xff0c;N是數據樣本的數量&#xff0c;D是數據的維度均值減法(Mean subtraction)&#xff1a;是預處理最常用的形…

C++ 中實現 `Task::WhenAll` 和 `Task::WhenAny` 的兩種方案

&#x1f4da; C 中實現 Task::WhenAll 和 Task::WhenAny 的兩種方案 引用&#xff1a; 拈朵微笑的花 想一番人世變換 到頭來輸贏又何妨日與夜互消長 富與貴難久長 今早的容顏老於昨晚C 標準庫異步編程示例&#xff08;一&#xff09;C TAP&#xff08;基于任務的異步編程…

【學習】Codeforces Global Round 15 C. Maximize the Intersections

題意&#xff1a;給出一個圓&#xff0c;順時針排布1~2*n&#xff0c;已知連了k條邊&#xff0c;問這個圓最好情況下有多少個線的交點&#xff0c;要求線與線之間不能有重復的連接點&#xff0c;也就是每個點只能被一條線連接 思路&#xff1a; 1.考慮沒有線的時候&#xff0…

圖論:Dijkstra算法

昨天介紹了最小生成樹的兩個算法&#xff0c;最小生成樹的兩個算法旨在求解無向有權圖中的最小代價聯通圖的問題&#xff0c;那么對于有向有權圖&#xff0c;從起點到終點的最小花費代價問題就可以用 Dijkstra 算法來解決而且Dijkstra算法可以求出來從起始點開始到所有節點的最…

WPFC#超市管理系統(2)顧客管理、供應商管理、用戶管理

超市管理系統3. 顧客管理3.1 顧客新增3.2 DataGrid樣式3.3 顧客刪除3.4 顧客修改4. 供應商管理4.1 供應商管理主界面4.2 新增供應商4.3 修改供應商5. 用戶管理5.1 用戶管理主界面5.2 新增用戶5.3 修改用戶總結3. 顧客管理 在CustomerView.xaml使用命令綁定方式添加頁面加載Loa…

Windows本地部署DeepSeek

1、Ollama1、下載Ollama安裝包https://ollama.com/download&#xff08;如果下載很慢 可以直接找我拿安裝包&#xff09;2、使用命令行安裝打開cmd 將下載的安裝包OllamaSetup.exe 放到想要安裝的目錄下。&#xff08;如果直接雙擊&#xff0c;會裝到C盤&#xff09;例如想裝到…

基于Python的新聞爬蟲:實時追蹤行業動態

引言 在信息時代&#xff0c;行業動態瞬息萬變。金融從業者需要實時了解政策變化&#xff0c;科技公司需要跟蹤技術趨勢&#xff0c;市場營銷人員需要掌握競品動向。傳統的人工信息收集方式效率低下&#xff0c;難以滿足實時性需求。Python爬蟲技術為解決這一問題提供了高效方…

阿里視頻直播解決方案VS(MediaMTX + WebRTC) 流媒體解決方案

背景&#xff1a; 公司采購了新的攝像頭&#xff0c;通過rtsp或者rtmp推流到云平臺&#xff0c;云平臺內部進行轉碼處理&#xff0c;客戶端使用HLS或HTTP-FLV播放&#xff0c;移動App可能使用HLS或私有SDK&#xff0c;超低延時則采用WebRTC。 技術選型&#xff1a; RTSP&…

day33:零基礎學嵌入式之網絡——TCP并發服務器

一、服務器1.服務器分類單循環服務器&#xff1a;只能處理一個客戶端任務的服務器并發服務器&#xff1a;可同時處理多個客戶端任務的服務器二、TCP并發服務器的構建1.如何構建&#xff1f;&#xff08;1&#xff09;多進程&#xff08;每一次創建都非常耗時耗空間&#xff0c;…

VR全景制作的流程?VR全景制作可以用在哪些領域?

VR全景制作的流程&#xff1f;VR全景制作可以用在哪些領域&#xff1f;VR全景制作&#xff1a;流程、應用與未來虛擬現實&#xff08;VR&#xff09;全景制作正迅速改變我們的感官體驗&#xff0c;使我們能夠身臨其境地探索虛擬世界&#xff0c;享受沉浸式的奇妙感受。那么&…

用LangChain重構客服系統:騰訊云向量數據庫+GPT-4o實戰

人們眼中的天才之所以卓越非凡&#xff0c;并非天資超人一等而是付出了持續不斷的努力。1萬小時的錘煉是任何人從平凡變成超凡的必要條件。———— 馬爾科姆格拉德威爾 目錄 一、傳統客服系統痛點與重構價值 1.1 傳統方案瓶頸分析 1.2 新方案技術突破點 二、系統架構設計&…

主要分布在腹側海馬體(vHPC)CA1區域(vCA1)的混合調諧細胞(mixed-tuning cells)對NLP中的深層語義分析的積極影響和啟示

腹側海馬體CA1區&#xff08;vCA1&#xff09;的混合調諧細胞&#xff08;mixed-tuning cells&#xff09;通過整合情感、社會關系、空間概念等多模態信息&#xff0c;形成動態的情景化語義表征&#xff0c;為自然語言處理&#xff08;NLP&#xff09;的深層語義分析提供了重要…

ESP32的ADF詳解:6. Audio Processing的API

一、Downmix 1. 核心功能 將基礎音頻流和新加入音頻流混合為單一輸出流&#xff0c;支持動態增益控制和狀態轉換。輸出聲道數與基礎音頻一致&#xff0c;新加入音頻自動轉換聲道匹配。2. 關鍵特性聲道處理 輸出聲道數 基礎音頻聲道數新加入音頻自動轉換聲道&#xff08;如立體…

Qt(基本組件和基本窗口類)

一、基本組件1. Designer設計師為什么要上來先將這個東西呢&#xff0c;這個是QT外置的設計界面的工具&#xff0c;沒啥用&#xff0c;所以了解一下。我們用的多的是QT內置的界面設計&#xff0c;只需要我們雙擊我們創建的項目的.ui文件就可以進入這個界面&#xff0c;你對界面…

docker與k8s的容器數據卷

Docker容器數據卷 特性 docker鏡像由多個只讀層疊加而成&#xff0c;啟動容器時&#xff0c;Docker會加載只讀鏡像層并在鏡像棧頂部添加一個讀寫層。如果運行中的容器修改了現有的一個已經存在的文件&#xff0c;那么該文件將會從讀寫層下面的只讀層復制到讀寫層&#xff0c;該…

自然語言處理技術應用領域深度解析:從理論到實踐的全面探索

1. 引言:自然語言處理的技術革命與應用前景 自然語言處理(Natural Language Processing,NLP)作為人工智能領域的核心分支,正在以前所未有的速度改變著我們的數字化生活。從最初的規則基礎系統到如今基于深度學習的大語言模型,NLP技術經歷了從理論探索到實際應用的深刻變…

OpenGLRender開發記錄(二): 陰影(shadowMap,PCF,PCSS)

目錄已實現功能陰影shadowMapPCFPCSS實現shadowMapPCFPCSS陰影GitHub主頁&#xff1a;https://github.com/sdpyy1 OpenGLRender:https://github.com/sdpyy1/CppLearn/tree/main/OpenGL 已實現功能 除了上次實現IBL之外&#xff0c;項目目前新增了imGUI的渲染&#xff0c;更方便…

Linux:日志亂碼

1、Linux日志亂碼可能是XShell客戶端編碼沒設置為UTF-8引起的&#xff0c;按照以下步驟&#xff0c;設置終端格式&#xff1a;中文版&#xff1a;打開Xshell會話屬性&#xff08;文件→屬性→終端→編碼&#xff09;&#xff0c;選擇與服務器一致的編碼格式&#xff08;如UTF-8…

Rouge:面向摘要自動評估的召回導向型指標——原理、演進與應用全景

“以n-gram重疊量化文本生成質量&#xff0c;為摘要評估提供可計算標尺” Rouge&#xff08;Recall-Oriented Understudy for Gisting Evaluation&#xff09; 是由 南加州大學信息科學研究所&#xff08;ISI&#xff09;的Chin-Yew Lin 于2004年提出的自動文本摘要評估指標&am…

[STM32][HAL]stm32wbxx 超聲波測距模塊實現(HY-SRF05)

前言 在電子技術應用中,距離測量是一個常見且重要的需求。超聲波模塊因其測量精度較高、成本較低、易于使用等優點,被廣泛應用于機器人避障、液位檢測、智能停車系統等領域。該文主要講解以stm32wb芯片為主控,用HAL庫來對HY-SRF05超聲波模塊進行代碼編寫,實現基本的驅動和測…