【LeetCode】只出現一次的數字系列問題(I、II、III)


(一)只出現一次的數字(其他兩次)

題目(Easy):136. 只出現一次的數字

題目描述:

給定一個非空整數數組,除了某個元素只出現一次以外,其余每個元素均出現兩次。找出那個只出現了一次的元素。

說明: 你的算法應該具有線性時間復雜度。 你可以不使用額外空間來實現嗎?

示例 1:

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

示例 2:

	輸入: [4,1,2,1,2]
	輸出: 4

解題思路:

  利用異或的性質
x ^ x = 0
0 ^ x = x,相同為0,相異為1,通過異或相同的數抵消掉了,剩下一個多余的數。

代碼實現:

class Solution {
    public int singleNumber(int[] nums) {
        int res=0;
        for(int num:nums){
            res ^= num;
        }
        return res;
    }
}

(二)只出現一次的數字II (其他三次)

題目(Medium):137. 只出現一次的數字 II

題目描述:

給定一個非空整數數組,除了某個元素只出現一次以外,其余每個元素均出現了三次。找出那個只出現了一次的元素。

說明: 你的算法應該具有線性時間復雜度。 你可以不使用額外空間來實現嗎?

示例 1:

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

示例 2:

	輸入: [0,1,0,1,0,1,99]
	輸出: 99

解題思路:

  方法一:

  統計所有數字中每個位中1出現的總數,那么對於某個位,1出現的次數一定是3的倍數+1或0,那么對這個數%3得到的結果就是目的數字在該位上的值。

  方法二:

  為了區分出現一次的數字和出現三次的數字,使用兩個位掩碼:seen_onceseen_twice

  思路是:

  • 僅當 seen_twice 未變時,改變 seen_once
  • 僅當 seen_once 未變時,改變seen_twice

代碼實現:

//方法一
class Solution {
    public int singleNumber(int[] nums) {
        int res=0;
        //依次考慮每一位
        for(int i=0;i<32;i++){
            int count=0;
            //統計該位1的總個數
            for(int num:nums){
                if((num>>i & 1)==1)
                    count++;
            }
            if(count%3!=0)
                res = res | (1<<i);
        }
        return res;
    }
}
//方法二:
class Solution {
    public int singleNumber(int[] nums) {
        int seenOnce = 0, seenTwice = 0;

    for (int num : nums) {
      // first appearence: 
      // add num to seen_once 
      // don't add to seen_twice because of presence in seen_once

      // second appearance: 
      // remove num from seen_once 
      // add num to seen_twice

      // third appearance: 
      // don't add to seen_once because of presence in seen_twice
      // remove num from seen_twice
      seenOnce = ~seenTwice & (seenOnce ^ num);
      seenTwice = ~seenOnce & (seenTwice ^ num);
    }

    return seenOnce;

    }
}

(三)只出現一次的數字III(兩個一次)

題目(Medium):260. 只出現一次的數字 III

題目描述:

給定一個整數數組 nums,其中恰好有兩個元素只出現一次,其余所有元素均出現兩次。 找出只出現一次的那兩個元素。

示例 :

	輸入: [1,2,1,3,2,5]
	輸出: [3,5]

解題思路:

  具體參見:【劍指Offer】40、數組中只出現一次的數字

  首先仍然從前向后依次異或數組中的數字,那么得到的結果是兩個只出現一次的數字的異或結果,其他成對出現的數字被抵消了。由於這兩個數字不同,所以異或結果肯定不為0,也就是這個異或結果一定至少有一位是1,我們在結果中找到第一個為1的位的位置,記為第n位。接下來,以第n位是不是1為標准,將數組分為兩個子數組,第一個數組中第n位都是1,第二個數組中第n位都是0。這樣,便實現了我們的目標。最后,兩個子數組分別異或則可以找到只出現一次的數字。

代碼實現:

class Solution {
    public int[] singleNumber(int[] nums) {
        int[] result=new int[2];
        //1、先把所有的數字異或一次,得到的是要找的兩個數的異或
        int res=0;
        for(int num:nums)
            res ^= num;
        
        //2、找到異或結果中第一個不為0的位
        int index=0;
        while(index<32){
            if(((res>>index)&1)==1)
                break;
            index++;
        }

        //3、按照第index位是0還是1分別異或
        for(int num:nums){
            if(((num>>index)&1)==1)
                result[0] ^= num;
            else
                result[1] ^= num;
        }
        return result;
    }
}

總結:

  只出現一次的數字這三道題,主要涉及到的是位運算的相應問題,特別是異或運算和移位運算的巧妙應用,位運算相對理解起來有一定的難度,需要深入理解。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM