LeetCode刷題-消失的兩個數(shù)字

前言說明

算法學(xué)習(xí),日常刷題記錄。

題目連接

消失的兩個數(shù)字

題目內(nèi)容

給定一個數(shù)組,包含從1到N所有的整數(shù),但其中缺了兩個數(shù)字。你能在O(N)時間內(nèi)只用O(1)的空間找到它們嗎?

以任意順序返回這兩個數(shù)字均可。

示例1:

輸入: [1]

輸出: [2,3]

示例2:

輸入: [2,3]

輸出: [1,4]

提示:

nums.length <= 30000

分析過程

思路:使用總和累減法,用總和累減法可以找出缺失的一個數(shù)字,而這里缺失的是兩個數(shù)字,那么先用總和累減法找出缺失的兩個數(shù)字的總和,總和除以2,確定切分的位置,切分為兩部分后,兩部分各缺失一個數(shù)字,第一部分再用總和累減法找出缺失的那個數(shù)字,再用原來缺失的兩個數(shù)字的總和減去找到的這個缺失的數(shù)字得到另一個缺失的數(shù)字,即可找到缺失的兩個數(shù)字。

第一步

計算整數(shù)范圍的長度size,因為是缺失兩個數(shù)字,所以整數(shù)范圍的長度是數(shù)組長度加2。

計算從1到N的總和sum,總和 = (首項 + 末項) * 數(shù)量 / 2。

第二步

遍歷數(shù)組,使用總和累減法,即用1到N的總和sum逐個減去數(shù)組的元素,最后得到缺失的兩個數(shù)字的總和,這時sum變成缺失的兩個數(shù)字的總和。

第三步

把缺失的兩個數(shù)字的總和sum除以2等于mid,因為題目說包含從1到N所有的整數(shù),所以數(shù)字不重復(fù),缺失的兩個數(shù)字一定是一個小于等于mid,另一個大于mid。

為何一個是小于等于mid?因為java中除以2,如果結(jié)果是小數(shù),那么會去掉小數(shù)點后的位向下轉(zhuǎn)轉(zhuǎn)換。例如:缺失的兩個數(shù)字是7和8,那么sum=15,15/2=7,這里就出現(xiàn)小于等于mid,而且從這里也可以看出,mid一定落在1到N的整數(shù)之間,因為1到N是連續(xù)的整數(shù)。

所以,數(shù)組被mid切分為了兩部分,兩部分各分布一個缺失的數(shù)字。

第四步

計算第一部分的總和sum1,即從1到mid的總和,總和 = (首項 + 末項) * 數(shù)量 / 2,這里的首項就是1,末項也是1,數(shù)量就是mid,即sum1 = (1 + mid) * mid / 2。

第五步

計算第一部分在數(shù)組中的總和sumOfLessMid,通過遍歷數(shù)組,累加得到,遍歷時小于等于mid的數(shù)字才是符合條件進行累加的,遍歷數(shù)組結(jié)束后,sumOfLessMid就是第一部分在數(shù)組中的總和。

第六步

定義第一部分中缺失的數(shù)字為one,定義第二部分中缺失的數(shù)字為two。

第一部分中缺失的數(shù)字 = 第一部分的總和 - 第一部分在數(shù)組中的總和,即one = sum1 - sumOfLessMid。

第一部分中缺失的數(shù)字計算出來后,那么用前面缺失的兩個數(shù)字的總和sum減去第一部分中缺失的數(shù)字one,就算出了第二部分中缺失的數(shù)字two。

第二部分中缺失的數(shù)字 = 缺失的兩個數(shù)字的總和 - 第一部分中缺失的數(shù)字,即two = sum - one。

最后返回兩個缺失的數(shù)字one和two組成的數(shù)組。

解答代碼

class Solution {
    public int[] missingTwo(int[] nums) {
        // 思路:總和累減法,用總和累減法可以找出缺失的一個數(shù)字,而這里缺失的是兩個數(shù)字,那么先用總和累減法找出缺失的兩個數(shù)字的總和,總和除以2,確定切分的位置,切分為兩部分后,兩部分各缺失一個數(shù)字,第一部分再用總和累減法找出缺失的那個數(shù)字,再用原來缺失的兩個數(shù)字的總和減去找到的這個缺失的數(shù)字得到另一個缺失的數(shù)字,即可找到缺失的兩個數(shù)字,不過這種方法先要保證不能總和不能溢出

        // 定義整數(shù)長度,因為缺失兩個數(shù)字,所以整數(shù)范圍是數(shù)組長度加2
        int size = nums.length + 2;

        // 計算從1到n的總和,總和=(首項+末項)*數(shù)量/2
        int sum = (1 + size) * size / 2;

        // 遍歷數(shù)組,總和累減數(shù)組的整數(shù),最后得到缺失的兩個數(shù)字的總和
        for (int num : nums) {
            sum -= num;
        }

        // 這時sum變成缺失的兩個數(shù)字的總和

        // 缺失的兩個數(shù)字的總和除以2,因為數(shù)字不重復(fù),所以缺失的兩個數(shù)字一個小于等于mid,另一個大于mid
        int mid = sum / 2;

        // 數(shù)組被切分為了兩部分,兩部分各分布一個缺失的數(shù)字

        // 計算第一部分的總和,即從1到mid的總和,總和=(首項+末項)*數(shù)量/2
        int sum1 = (1 + mid) * mid / 2;

        // 定義第一部分在數(shù)組中的總和
        int sumOfLessMid = 0;

        // 遍歷數(shù)組,累加得到第一部分在數(shù)組中的總和
        for (int num : nums) {
            if (num <= mid) {
                // 小于等于mid的數(shù)字是符合條件的
                sumOfLessMid += num;
            }
        }

        // 第一部分中缺失的數(shù)字=第一部分的總和-第一部分在數(shù)組中的總和
        int one = sum1 - sumOfLessMid;
        // 第二部分中缺失的數(shù)字=缺失的兩個數(shù)字的總和-第一部分中缺失的數(shù)字
        int two = sum - one;

        // 返回兩個缺失的數(shù)字組成的數(shù)組
        return new int[]{one,two};
    }
}

提交結(jié)果

執(zhí)行用時1ms,時間擊敗100.00%的用戶,內(nèi)存消耗39.9MB,空間擊敗61.54%的用戶。

運行結(jié)果

原文鏈接

原文鏈接:消失的兩個數(shù)字

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容