文的盲刷LeetCode 15. 三數(shù)之和(3Sum)

中文題目

給定一個(gè)包含 n 個(gè)整數(shù)的數(shù)組 nums购对,判斷 nums 中是否存在三個(gè)元素 a啡浊,b觅够,c 胶背,使得 a + b + c = 0 ?找出所有滿足條件且不重復(fù)的三元組喘先。

注意:答案中不可以包含重復(fù)的三元組钳吟。

例如, 給定數(shù)組 nums = [-1, 0, 1, 2, -1, -4],

滿足要求的三元組集合為:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

英文題目

Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

The solution set must not contain duplicate triplets.

Example:

Given array nums = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

解法一:

直接暴力求解窘拯,三變量红且,逐個(gè)循環(huán),算法時(shí)間復(fù)雜度大致為n^3涤姊,超時(shí)應(yīng)該是沒有任何問題直焙,所以我并未嘗試,后來看網(wǎng)上相關(guān)題解砂轻,直接暴力的的確會超時(shí)

解法二:

既然暴力會直接超時(shí)奔誓,那么如何優(yōu)化呢?

—— 排序后再求解如何搔涝,排序作為重要且非常常用的算法厨喂,確實(shí)可以將許多問題變得簡單化

選用何種排序?

—— 為了降低時(shí)間復(fù)雜度庄呈,為之后的操作留下空間蜕煌,所以,選擇快排或者歸并

原始思路:

我剛開始想的是:

  • 將兩個(gè)指針指向數(shù)組兩邊诬留,直至左邊大于右邊(此用while構(gòu)成一組循環(huán))

  • 再一指針置于左右的中間(此用for 構(gòu)成一重循環(huán))斜纪,直至等于右邊-1

但是在提交過程中遇到了困難,后經(jīng) 博客提點(diǎn)文兑,發(fā)現(xiàn)自己的寫法不甚理想盒刚,遂改之

最終通過代碼如下:

/**
 * Return an array of arrays of size *returnSize.
 * Note: The returned array must be malloced, assume caller calls free().
 */
void Merge(int a[], int l, int r, int rightEnd, int temp[]) {
    int leftEnd = r-1 ;
    int left = l, tmp = l;

    while (l <= leftEnd && r <= rightEnd){ // 當(dāng)左右子序列均不空
        if (a[l] > a[r])
            temp[tmp++] = a[r++];
        else
            temp[tmp++] = a[l++];
    }
    while (l <= leftEnd)
        temp[tmp++] = a[l++];
    while (r <= rightEnd)
        temp[tmp++] = a[r++];
    for (int i = left; i < rightEnd + 1; i++)
        a[i] = temp[i];
}


void MergeSort(int a[], int l, int rightEnd, int temp[]) {
    int center;
    if (l < rightEnd) {
        center = (l + rightEnd) / 2;
        MergeSort(a, l, center, temp);
        MergeSort(a, center + 1, rightEnd, temp);
        Merge(a, l, center+1, rightEnd, temp);
    }
}


void Merge_sort(int a[], int n) {
    int* tmpA;
    tmpA = malloc(n * sizeof(int));
    if (tmpA != NULL){
        MergeSort(a, 0, n-1, tmpA);
        free(tmpA);
    } else {
        printf("ERROR");
    }
}


int** threeSum(int* nums, int numsSize, int* returnSize) {
    if (numsSize < 3)
        return NULL;
    int i = 0, j, k, temp, count = 0;
    int** result=(int**)malloc(sizeof(int*)*(numsSize*(numsSize-1)*(numsSize-2))/6);
    Merge_sort(nums, numsSize);
    for (i = 0; i < numsSize; i++){
        if (nums[i] > 0)
            break;
        if (i > 0 && nums[i] == nums[i-1])  // 跳過重復(fù)負(fù)數(shù)
            continue;
        j = i+1;
        k = numsSize-1;
        while (j < k){
            temp = nums[i]+nums[j]+nums[k];
            if (temp == 0){
                result[count] = (int*)malloc(sizeof(int)*3);
                result[count][0] = nums[i];
                result[count][1] = nums[j];
                result[count][2] = nums[k];
                count++;
                j++;    k--;
                while (j <k && nums[j] == nums[j-1])    // 跳過重復(fù)數(shù)字
                    j++;
                while (j < k && nums[k] == nums[k+1])   // 跳過重復(fù)數(shù)字
                    k--;
            } else if (temp > 0)    // 右邊數(shù)字過大 
                k--;
            else    // 左邊數(shù)字過小
                j++;
        }
    }
    
    *returnSize = count;
    return result;
}

代碼解釋:

首先前三個(gè)函數(shù)實(shí)現(xiàn)歸并排序,void Merge_sort(int a[], int n)函數(shù)簡化函數(shù)接口绿贞,相關(guān)代碼實(shí)現(xiàn)借鑒 浙江大學(xué)慕課——數(shù)據(jù)結(jié)構(gòu)

主體函數(shù)采用二重循環(huán)因块,時(shí)間復(fù)雜度接近n^2

  1. 初始化數(shù)據(jù)
  2. 將數(shù)組nums從小到大排序
  3. 第一重循環(huán)為取出所有負(fù)數(shù)nums[i]
  4. 第二重循環(huán)為從i+1開始numsSize-1結(jié)束,查找是否存在三數(shù)之和為0

代碼說明:

  • 注意用指針的指針表示動態(tài)數(shù)組時(shí)的malloc()過程
LeetCode15.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末籍铁,一起剝皮案震驚了整個(gè)濱河市涡上,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拒名,老刑警劉巖吩愧,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異增显,居然都是意外死亡雁佳,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甘穿,“玉大人腮恩,你說我怎么就攤上這事梢杭∥录妫” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵武契,是天一觀的道長募判。 經(jīng)常有香客問我,道長咒唆,這世上最難降的妖魔是什么届垫? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮全释,結(jié)果婚禮上装处,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布阅茶。 她就那樣靜靜地躺著未巫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谦炬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機(jī)與錄音黔州,去河邊找鬼。 笑死阔籽,一個(gè)胖子當(dāng)著我的面吹牛流妻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播笆制,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼合冀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了项贺?” 一聲冷哼從身側(cè)響起君躺,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎开缎,沒想到半個(gè)月后棕叫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奕删,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年俺泣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡伏钠,死狀恐怖横漏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情熟掂,我是刑警寧澤缎浇,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站赴肚,受9級特大地震影響素跺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜誉券,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一指厌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧踊跟,春花似錦踩验、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至决帖,卻和暖如春厕九,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背地回。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工扁远, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人刻像。 一個(gè)月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓畅买,卻偏偏與公主長得像,于是被迫代替她去往敵國和親细睡。 傳聞我的和親對象是個(gè)殘疾皇子谷羞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容