1. 程式人生 > 實用技巧 >【Python】where cut query melt函式用法

【Python】where cut query melt函式用法

題目描述

一個整型陣列 nums 裡除兩個數字之外,其他數字都出現了兩次。請寫程式找出這兩個只出現一次的數字。要求時間複雜度是\(O(n)\),空間複雜度是\(O(1)\)

示例1:

輸入:nums = [4,1,4,6]
輸出:[1,6] 或 [6,1]

示例2:

輸入:nums = [1,2,10,4,1,4,3,3]
輸出:[2,10] 或 [10,2]

限制:

2 <= nums.length <= 10000

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof

程式碼實現

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        int diff = 0;
        for(auto nt = nums.begin(); nt != nums.end(); nt++) 
            diff ^= (*nt);
        int flag = diff & (-diff);
        vector<int> result(2, 0);
        for(auto nt = nums.begin(); nt != nums.end(); nt++) {
            if((*nt) & flag)
                result[0] ^= (*nt);
            else
                result[1] ^= (*nt);
        }
        return result;
    }
};

思路解析

  • 題目的重點是要時間複雜度\(O(n)\),空間複雜度\(O(1)\),考慮位運算的方式;
  • 基本的位運算邏輯:
    • 使用邏輯異或(\(\oplus\))來區分未成對出現的數字
      \(0 \oplus 0 = 0\)\(0 \oplus 1 = 1\)
    • 邏輯異或(\(\oplus\))運算滿足結合律和交換律;
      因此,對所有的數字進行異或運算,由於只有兩個數字(假設為\(a\)\(b\))未重複出現,則異或運算的結果是\(a\oplus b\)
      \(a_1 \oplus a_1 \oplus a_2 \oplus a_2 \oplus \cdots a_n \oplus a_n \oplus k = k\)
  • 得到\(a\oplus b\)後,我們需要想一個辦法來將nums分組,考慮所有的數字都可以用二進位制表示,則可根據某一位是\(0\)\(1\)來對nums進行分組,且要保證\(a\)\(b\)不在同組,採用的分組方式如下:
    • 在計算機中,整形數字採用補碼的形式表示,正數的補碼等於其原碼,負數的補碼等於其反碼+1,以8位int型別為例:
      int s = 8,原碼00000100,反碼00000100,補碼00000100
      int s =-8,原碼10000100,反碼11111011,補碼11111100
    • 可知:s & (-s) = 00000100,僅有1位數字為\(1\)s的最低位\(1\)),且s本身的該位數字也為1,可利用這一特性,對原陣列nums進行分類。
    • 如何確保\(a\)\(b\)不在同一分組?
      已知\(d = a\oplus b\),則\(d\)的最低位\(1\)一定可以區分\(a\)\(b\)(異或運算的定義)
      則根據\(d\)的某一位\(1\)對原陣列進行分組,必定可保證\(a\)\(b\)不同組。
  • 分組之後的事情就簡單了,由於異或運算滿足結合律和交換律,且相同的數字一定被分在的同一組,而\(a\)\(b\)不同組,對每一組分別進行異或運算,最後兩組得到的結果就分別是\(a\)\(b\)