//
// E_268_MissingNumber.swift
// AlgorithmLeetCode
//
// Created by okerivy on 2017/3/9.
// Copyright ? 2017年 okerivy. All rights reserved.
// https://leetcode.com/problems/missing-number
import Foundation
// MARK: - 題目名稱: 268. Missing Number
/* MARK: - 所屬類別:
標簽: Array, Math, Bit Manipulation
相關題目:
(H) First Missing Positive
(E) Single Number
(M) Find the Duplicate Number
*/
/* MARK: - 題目英文:
Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missing from the array.
For example,
Given nums = [0, 1, 3] return 2.
Note:
Your algorithm should run in linear runtime complexity. Could you implement it using only constant extra space complexity?
Credits:
Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases.
*/
/* MARK: - 題目翻譯:
給定一個數組,數組包含 n 個取自 0, 1, 2, ..., n 的不同的數字,從數組中找到丟失的那個數字。
例如:給定 nums = [0, 1, 3] 返回 2.
注意:
你的算法應當使用線性的時間復雜度(即時間復雜度為O(n))。你能夠只使用常量的額外空間來解決這題嗎?
*/
/* MARK: - 解題思路:
1.
從 0, 1, 2, ..., n 中取 n 個不同的數字組成數組 nums,尋找丟失的那個數字,非常自然的想法就是將 0, 1, 2, ..., n 加和之后,減去數組 nums 的和就得到了丟失的那個數字。
思路非常簡單。但是為了避免加和造成的溢出,
這里有一個小技巧:即不需要將兩個數組先加起來之后再做減法,可以邊加邊減。
例如 數組
數字 0 1 3 4 5 6 7 8 // 缺失的是 2
下標 0 1 2 3 4 5 6 7 // 8個元素
進行相加相減運算 上下全部進行 (i - nums[i])
0-0+1-1+3-2+4-3+5-4+6-5+7-6+8-7 = 0-0 1-1 3-3 4-4 5-5 6-6 7-7 2-8 = 2-8
(i - nums[i]) = 2-8
可以看到 2 已經出來了 因為 nums.count = 8 所以再次相加一次 ans + (i - nums[i])
nums.count + 2-8 = 8 + 2-8 = 2
2.
其基本思想是利用異或XOR運算。我們都知道一個a^b^b =a,這意味著相同數量的兩異或操作將消除數量和揭示原數。
在這個解決方案中,我運用異或XOR操作的指標和數組的值。
在一個沒有缺數字完整的陣列,指標值應完全對應(nums[index] = index),所以在丟失數組,剩下的最后是失蹤數字。
例如 數組
數字 0 1 3 4 5 6 7 8 // 缺失的是 2
下標 0 1 2 3 4 5 6 7 // 0..7 有8個元素
進行異或運算 上下全部進行 (i ^ nums[i])
0^0^1^1^3^2^4^3^5^4^6^5^7^6^8^7 = 0^0^1^1^3^3^4^4^5^5^6^6^7^7^8^2 = 8^2
(i ^ nums[i]) = 8^2
可以看到 2 已經出來了 因為 xor = nums.count = 8 所以再次異或一次 xor ^ (i ^ nums[i])
8^2^nums.count = 8^2^8 = 2
---------------------------------
異或是一種基于二進制的位運算,用符號XOR或者 ^ 表示,
其運算法則是對運算符兩側數的每一個二進制位,同值取0,異值取1。
異或的性質
交換律:a ^ b = b ^ a
結合律:a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c
d = a ^ b ^ c 可以推出 a = d ^ b ^ c
自反性:a ^ b ^ a = b
算法題目
①1-1000放在含有1001個元素的數組中,只有唯一的一個元素值重復,其它均只出現一次。每個數組元素只能訪問一次,設計一個算法,將它找出來;不用輔助存儲空間,能否設計一個算法實現?
前面提到異或具有交換律和結合律,所以1^2^...^n^...^n^...^1000,無論這兩個n出現在什么位置,都可以轉換成為1^2^...^1000^(n^n)的形式。
其次,對于任何數x,都有x^x=0,x^0=x。
所以1^2^...^n^...^n^...^1000 = 1^2^...^1000^(n^n)= 1^2^...^1000^0 = 1^2^...^1000(即序列中除了n的所有數的異或)。
令,1^2^...^n^..^1000(序列中包含一個n)的結果為T
則1^2^..^n^..^n^..^1000(序列中包含2個n)的結果就是T^n。
T^(T^n)=n。
所以,將所有的數全部異或,得到的結果與1^2^3^...^1000的結果進行異或,得到的結果就是重復數。
*/
/* MARK: - 復雜度分析:
間復雜度是O(n),空間復雜度為O(1)
*/
// MARK: - 代碼:
private class Solution {
// 加法求和
func missingNumber(_ nums: [Int]) -> Int {
var ans = 0
for i in 0..<nums.count {
ans = ans + i - nums[i]
}
ans += nums.count
return ans
}
// 異或運算
func missingNumber2(_ nums: [Int]) -> Int {
var xor = nums.count
for i in 0..<nums.count {
xor = xor ^ i ^ nums[i];
}
return xor;
}
}
// MARK: - 測試代碼:
func missingNumber() {
print(Solution().missingNumber([0, 1, 3, 4, 5, 6, 7]))
print(Solution().missingNumber([1, 2, 3, 4, 5]))
print(Solution().missingNumber([0, 1, 2, 4, 5]))
print(Solution().missingNumber([5, 1, 2, 0, 4]))
}