劍指offer 004 只出現一次的數字
題目
給你一個整數數組 nums ,除某個元素僅出現 一次 外,其餘每個元素都恰出現 三次 。請你找出並返回那個只出現了一次的元素。
示例 1:
輸入:nums = [2,2,3,2]
輸出:3
示例 2:
輸入:nums = [0,1,0,1,0,1,100]
輸出:100
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/WGki4K
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
題解:
方法一:排序+棧
思路:首先先排序,排序結束之後將數字依次壓棧,壓棧條件是棧頂元素和待入棧元素如果相同的話,入棧。最後只剩下一個元素的數字。
public int singleNumber(int[] nums) {
Arrays.sort(nums);
Deque<Integer> stack = new ArrayDeque<>();
int idx = 0;
for (int num : nums) {
if (stack.isEmpty() || stack.peek() == num) {
stack.push(num);
idx++;
}
if (idx == 3) {
stack.clear();
idx=0;
}
}
return stack.peek();
}
這種效率比較低。不推薦。
方法二:雙指針+排序
指定左右指針,左指針指向最左端,右指針指向第三個元素,如果這兩個數字相等,則證明這三個數字是相同的,判斷下一組三個數字即可。否則的話,返回最左端的元素。
public int singleNumber(int[] nums) {
Arrays.sort(nums);
int left = 0,right = 2;
int n = nums.length;
while (right<n){
if(nums[left] != nums[right]){
return nums[left];
}
left = left+3;
right = left+2;
}
return nums[left];
}
比較推薦這種方法,效率比較好。
方法三:位運算
參考題解
由於整個數組除了目標數字,其餘所有的數都出現了三次,因此可以考慮對於數組中的每一個數如果按位求和的話那麼所求的和對3進行取餘之後,如果該位的數字都出現了三次,那麼餘數一定是0,反之如果不是0,那麼該位的數字(其實這個數字一定是1)一定是那個單獨出現一次的數字所佔的位。
步驟:
遍歷數字的每一位,因爲數據大小不超過整形範圍,因此遍歷在範圍[0,31]即可。
求和:對數組中的每一個數進行右移同時與1進行與運行算,獲得當前位數字加入到sum當中。
取餘,同時在將和右移i位加入到結果當中。
代碼:
class Solution {
public int singleNumber(int[] nums) {
int ans = 0;
for (int i = 0; i < 32; i++) {
int sum = 0;
for (int num : nums) {
sum += ((num >>= i) & 1);
}
sum %= 3;
ans += (sum << i);
}
return ans;
}
}
方法四:HashMap記錄次數
只講思路,最開始想到的方法,但是肯定效率特別低,有可能都通不過測試用例,只是提供一種思路。
首先,遍歷數組,將數組出現的次數以key爲數組中的數字,value爲數組出現的次數,存進map後,遍歷map,取出value爲1的值。