1. 程式人生 > >SINGLE NUMBER I & II & III

SINGLE NUMBER I & II & III

Single Number I :

Given an array of integers, every element appears twice except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

Solution:

解法不少,貼一種:

複製程式碼
1 class Solution:
2     # @param {integer[]} nums
3 # @return {integer} 4 def singleNumber(self, nums): 5 ans = nums[0]; 6 for i in range(1, len(nums)): 7 ans ^= nums[i] 8 return ans
複製程式碼

其依據在於:

1、異或運算滿足交換律;

2、a ^ a = 0;

3、b ^ 0 = b。

這題的關鍵就在於線性時間內把相同的一對 “消掉”,留下那個 “落單” 的。

異或運算給了這樣的快捷的可能。

Single Number II:

Given an array of integers, every element appears three times except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

Solution:

同樣,考慮用位運算解題:

在 I 中巧妙地用異或運算解決了把重複的元素的“消除”,只留下“落單”的元素的問題。而在 II 中,除了要找的元素,每個元素都出現 3 次,I 的解法適用於出現偶數次的情況,但對於奇數次已不再適用。

考慮每個數用二進位制展開,將各個數橫向比較:

對於一個32位(或者64位)的整數,對於這32個位中的某個位而言,如果每個數都出現三次,那麼對於所有數在這個位上“1”的個數,一定是 3 的倍數;而反之,如果存在某個數不是出現 3 次(也不是 3 的倍數次,這是題目未講明處,I 亦同理如此),那麼對於它的二進位制展開後數為 1 的位而言,對於所有數在這個位上“1”的個數,一定不是 3 的倍數。

所以具體的解決辦法是:

用一個 32 長的陣列儲存對於所有數的二進位制展開,每一個位上總共 “1” 的個數和,最後看那些位上 “1” 的個數不是 3 的倍數,那麼這一位在 ans 中就是 1。

演算法是 O(32n) 的。

有一點需要注意的是:

不同的語言中對位運算尤其是符號位的處理是不盡相同的,比如 C++ 中最高位是符號位,如果不是 3 的倍數那麼最後的 ans 就是負數,符號位可以和其他位一樣處理;但如果是Python,由於其動態型別的特性,當超出資料範圍時,會自動轉化為更大範圍的資料型別,而不會將其作為符號位處理。

C++版本:

複製程式碼
 1 class Solution {
 2 public:
 3     int singleNumber(int A[], int n) {
 4         int bitnum[32] = {0};
 5         int res=0;
 6         for(int i = 0; i < 32; i++){
 7             for(int j = 0; j < n; j++){
 8                 bitnum[i] += (A[j] >> i) & 1;
 9             }
10             res |= (bitnum[i] % 3) << i;
11         }
12         return res;
13     }
14 };
複製程式碼

Python版本:

複製程式碼
 1 class Solution:
 2     # @param {integer[]} nums
 3     # @return {integer}
 4     def singleNumber(self, nums):
 5         bitNum = [0] * 32
 6         for i in range(32):
 7             for e in nums:
 8                 bitNum[i] += (e >> i) & 1
 9         ans = 0
10         for i, val in enumerate(bitNum):
11             if i == 31 and val % 3 != 0:
12                 ans = -((1 << i) - ans)
13             else:
14                 ans |= (val % 3) << i
15         return ans
複製程式碼

其中對於邏輯上的符號位(第32位),單獨判斷並處理,如果為 1,則需要轉化為對應的負數(對應的負數的絕對值 = 【模】- 不考慮符號位(符號位為0)的正數)。

Single Number III

Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.

For example:

Given nums = [1, 2, 1, 3, 2, 5], return [3, 5].

Note:

  1. The order of the result is not important. So in the above example, [5, 3] is also correct.
  2. Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?

Credits:
Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases.

Solution:

打怪打到系列第三級,又回到了跟 I 類似的情況,也就是相同的數字是偶數個,不同的是,這裡面有兩個“怪胎”。

很容易聯想到 I 的解法,把所有數異或起來。但是異或之後我們得到的是我們想要的那兩個數的異或值,如何把它們從異或中拆分開呢?

假設我們要找的這兩個數為 a, b, 而 x = a ^ b。

首先,a 肯定不等於 b,那麼說明它們的二進位制位一定是不完全相同的,所以 x 肯定不為 0。

也就是說,a 與 b 一定存在“某一位”,使得在它們中的某個數中是 0,而在另一個數中是 1,這是他們之間的一個差別。

我們可不可以利用這個差別來把這兩個數從 x 中揪出來呢?

是可以的。

利用這個差別,我們可以將整個 nums 集合分成兩個集合。一個集合中是這 “某一位” 為 0 的在nums中的所有數,假設為集合 A。而另一個集合是這 “某一位” 為 1 的在nums中的所有數。假設 a 的這 “某一位” 是 0 ,b 的 這個“某一位”是1,那麼顯然 a 在集合 A 中,b 在集合 B 中,這樣問題就完全轉化成了與 I 一樣的兩個子問題,於是可以得解。

關於具體的程式碼實現,還有一點說明:

我們如何找到這個 “某一位” 呢?理論上,只要是在這一位上 a與b的值不同,都可以合格的成為我們需要找的某一位。既然無更多限制,那我們肯定是找好找的某一位咯。

我們可以用很常規和易懂的方法去找,但一般而言,我們肯定是找最右邊(低位)那邊符合要求的“某一位”嘛。更進一步說,就是找到 x 中最低位的 1 嘛。那當然我們可以從最低位開始列舉每一位,直到找到我們需要找的那個“某一位”。

還有一種更trick利用位運算的辦法:找到 x 中最低位的 1,仔細想想,這跟另外一個已經熟知的問題很像。

當我們統計某個數的二進位制展開中1的個數的時候,我們使用了一個技巧,即用 n &= n - 1 每次來清除 n 中當前最右邊的那個 1。

n-1 是把 n 的最低位的 1 變成 0,並且使更低位的 0 全部變成 1,然後異或一下就把 最低位的 1 及其更低位全部都變成了 0,即達到了“清除最低位的 1 的目的”。

在這個地方,我們需要逆向思維,即 保留 最低位的1,並且最好使得其他位 都變成0,這樣我直接與 nums 中的每一個數相與,就可以直接將它們分成 A 和 B 兩個集合了。

逆向思維會是這樣:

n-1 的過程其實是把 最低位 1 和 跟低位 都位反轉 (Bit Flipping) 的過程,那我們這裡 首先也將 n 的所有位反轉得到 n'。

然後我們再把 n'+1。。。

Opps! What did we get? 

我們發現 n'+1 相對於 n 而言,最低位的1及其更低位的0 都沒變,而其他位(比 最低位1 更高的位)都反轉了。

那此時如果用 n & (n'+1) 得到的便是 除 n 中最低位 1 繼續為 1 以外,其他各位都為 0 的數了。

n' 如何求?當然我們可以直接取反。但是聯合 n'+1 來看,各個位取反再加一,這不正是計算機中 “負數補碼” 的表示方式!

所以我們可以直接用 n &= -n 得到 “除 n 中最低位 1 繼續為 1 以外,其他各位都為 0 的數”!

(注意正數的補碼的補碼是它本身,所以即便 n 本身是負數,-n是正數,但 -n 依然是求 n 的補碼。)

完美!

程式碼如下:

複製程式碼
 1 class Solution:
 2     # @param {integer[]} nums
 3     # @return {integer[]}
 4     def singleNumber(self, nums):
 5         diff = 0
 6         for e in nums:
 7             diff ^= e
 8         diff &= -diff
 9         ans = [0, 0]
10         for e in nums:
11             if diff & e != 0:
12                 ans[0] ^= e
13             else:
14                 ans[1] ^= e
15         return ans
複製程式碼

相關推薦

SINGLE NUMBER I & II & III

Single Number I : Given an array of integers, every element appears twice except for one. Find that single one. Note: Your algorithm s

LeetCode Single Number I & II 都符合兩個問題額外要求的 通用解法 與 思考過程

 Single Number Given an array of integers, every element appearstwiceexcept for one. Find that single one. Note: Your algorithm should ha

&lt;LeetCode OJ&gt; 26 / 264 / 313 Ugly NumberI / II / III

規劃 fig enter 復制 popu margin man vector int Write a program to check whether a given number is an ugly number. Ugly numbers

LeetCode(41) Single Number III

Single Number I 題目描述 Given an array of integers, every element appears twice except for one. Find that single one. 如果一個給定陣列中除了一個元素其他所有元素均出

LeetCode Missing Number ,SingleNumber I II III

原文地址: 基本問題 問題描述: 給定一個數組, 其中有一個數出現了p次, 其他數都出現了k次, 找出出現p次的數(其中 p>0 p%k != 0), 求出現p次的數. 基本問題解法 一,32 個計數器 對於一個32 bit 的整

LeetCode - Two Sum I - II - III - IV、3Sum、3Sum Closest、4Sum、4Sum II 系列學習總結

目錄 1 - Two Sum 2 - Two Sum II - Input array is sorted 3 - Two Sum III - Data structure design 4 - Two Sum IV - Input is a BST 5 - 3Sum

LintCode 買賣股票的最佳時期I II III 之Python 程式碼

假設你有一個數組,它的第i個元素是一支給定的股票在第i天的價格。設計一個演算法來找到最大的利潤。 I:如果你最多隻允許完成一次交易。 II:你可以完成儘可能多的交易(多次買賣股票)。 III:你最多可以完成兩筆交易。 買賣股票的最佳時期I (I)簡單粗

買賣股票最佳時機(I II III IV 冷凍期,手續費)

共6個問題: 買賣股票最佳時機 買賣股票最佳時機 II 買賣股票最佳時機 III 買賣股票最佳時機 IV 最佳買賣股票時機含冷凍期 買賣股票最佳時機含手續費 分析: 只允許一次交易的最大收益(一次買進賣出)動態規劃: dp[i] = max(dp[i-1],

LeetCode (39) Ugly Number I II (醜數)

Ugly Number I 題目描述 Write a program to check whether a given number is an ugly number. Ugly numbers are positive numbers whose prime factor

LintCode 買賣股票的最佳時機I II III IV

今天我做了LintCode上的買賣股票系列題目。總共4道題目,主要使用了動態規劃的方法,在此寫出我的程式碼和思路以便交流和回顧。 1.假設有一個數組,它的第i個元素是一支給定的股票在第i天的價格。如果你最多隻允許完成一次交易(例如,一次買賣股票),設計一個演算法來找出最大

LeetCode136 Single Number, LeetCode137 Single Number II, LeetCode260 Single Number III

136. Single Number Given an array of integers, every element appears twice except for one. Find that single one. (Easy) Note:Your algorithm should have a l

Single Number II

什麽 -a 操作 javascrip word www keyword java 異或運算 題目描寫敘述 鏈接地址 解法 算法解釋 題目描寫敘述 Given 3*n + 1 numbers, every numbers occu

【Leetcode】137. Single Number II

val tar urn arr ber and mos calc cal 題目: Given an array of integers, every element appears three times except for one. Find that single o

[LeetCode] 137. Single Number II (位運算)

清零 一次 .com blog 適用於 soft hat ever rip 傳送門 Description Given an array of integers, every element appears three times except for one, w

lintcode83- Single Number II- midium

特征 except find class n+2 urn 出現一次 情況 write Given 3*n + 1 numbers, every numbers occurs triple times except one, find it. Given [1,1,2,3,

137.Single Number II

cnblogs 耗時 get html -i scrip details 每一個 [0 題目鏈接:https://leetcode.com/problems/single-number-ii/description/ 題目大意:給出一串數,每個數都出現三次,只有一個數只出現

[LeetCode] 260. Single Number III 單獨數 III

[1] log obj rec 就是 its begin find self Given an array of numbers nums, in which exactly two elements appear only once and all the other e

[LeetCode] 137. Single Number II 單獨數 II

input .cn targe 單獨 sin logs eve tput controls Given a non-empty array of integers, every element appears three times except for one, whic

LeetCode 137. Single Number II

without 當前 with 結果 example println ould 等於 記錄 分析 參考https://cloud.tencent.com/developer/article/1131945 我們想要達到的效果其實是——            a b 初

leetcode【260】Single Number III

寫在最前面: 當然可以通過遍歷查詢,但是時間複雜度太高,leetcode肯定通不過。 然後我們要研究異或。   leetcode【260】Single Number III Given an array of numbers nums, in which