左神讲算法——超级水王问题(详解)
本文根據左神課程學習總結而來:2021最新左神數據結構算法全家桶
超級水王問題:給你一個數組,出現次數大于數組長度的一半的元素稱之為水王數,怎么能快速找到水王數?
內存限制:時間復雜度O(n),額外空間復雜度O(1)——也就是遍歷數組的次數為有限次,申請的變量數為有限個
方式一:暴力法
暴力法的思想很簡單,用一個hashmap來存放數組中每個元素及其對應的數量,最后遍歷hashmap判斷有無元素數量大于數組長度一半,有則直接返回水王數,否則返回-1
public static int verify(int[] arr) {if (arr == null || arr.length == 0)return -1;//新建hashmap用于存放數組中每個元素及其對應的數量HashMap<Integer, Integer> hashMap = new HashMap<>();//遍歷數組的每個元素for(int num:arr){//如果hashmap中包含該元素,則將該元素的數量+1if(hashMap.containsKey(num))hashMap.put(num,hashMap.get(num)+1);//如果hashmap中不包含key,則將該元素的數量置為1elsehashMap.put(num,1);}//遍歷hashmap中每一個entry<k,v>for(Map.Entry<Integer,Integer> record:hashMap.entrySet()){if(record.getValue()>(arr.length>>1))//這里采用位運算,速度快//返回水王數return record.getKey();}return -1; }顯然,該方法不符合題目的限制,由于使用了hashmap,所以額外的空間復雜度為O(N)
方法二
如何使用有限變量遍歷有限次數來完成呢?
思路:從數組第一個元素開始,依次刪掉兩個不同的數,最后如果有水王數的話,它會剩下來(反過來不成立,也就是剩下來的數不一定是水王數)
如上圖所示,依次刪除兩個不同的元素,相同則不刪除,最后只剩下3即是水王數
但請注意,剩下的不一定是水王數,比如:12345,刪掉12、34還剩5,但是5不是水王數
這是什么原理呢?我們假設一個數組中有水王數,由于水王數的個數大于所有元素個數的一半,所以如果拿一個非水王數抵消一個水王數,最后還是會剩下水王數;上述刪除不同元素的過程就是如此,還可能會存在兩個非水王數互相抵消的情況,這樣水王數剩下的會更多。
因此我們的算法可以轉換為以下兩步:
怎么實現呢?我們只需要兩個變量,變量一candidate作為候選用來存放可能的水王數,變量二hp用來存放其剩余個數,按如下規則遍歷數組:
- hp=0 代表沒有candidate候選數;hp>0 代表有candidate候選數
- 如果沒有candidate,則設置當前數賦予candidate,即將當前數作為候選數,hp設置為1
- 如果有candidate,判斷當前數是否等于candidate,相等則hp+1,不相等則hp-1
最后判斷看hp是否為0,如果不為0,則代表有可能的水王數,再進行計數判斷即可
代碼實現:
public static int waterKing(int[] arr) {if (arr == null || arr.length == 0)return -1;int candidate = 0;int hp = 0;for (int cur : arr) {if (hp == 0) {//沒有候選,則將當前數設為候選candidate = cur;hp++;} else if (cur != candidate)//有候選且當前數!=侯選數hp--;else//有候選且當前數=候選數hp++;}//沒有候選數剩余,則沒有水王數if (hp == 0)return -1;//計算候選數在數組中的元素個數int count = 0;for (int num : arr) {if (num == candidate)count++;}//如果候選數元素個數>數組長度的一半則返回,否則返回-1return count > (arr.length >> 1) ? candidate : -1; }總結
以上是生活随笔為你收集整理的左神讲算法——超级水王问题(详解)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 轻量模型简介
- 下一篇: 云计算 - 虚拟化技术 - 总结