Merage Sort以及兩道leetCode的相關問題

merage sort

Divide-and-conquer

merge sort 的核心理念是 Divide-and-conquer 仰泻,這個范式的核心是把問題分割成跟原問題相似的子問題词疼,然后,遞歸的解決這些子問題鹃操,最后把這些子問題的結論合并得到原始問題的答案坯约。Divide-and-conquer 分三步:

  1. Divide 把問題分割成跟原來的問題一致但是規(guī)模變小了的子問題。
  2. Conquer 遞歸的解決子問題。如果問題足夠小了什燕,直接解決子問題。
  3. Combine 把子問題的解決方案合并的到原問題的解決方案竞端。

如圖所示:

mergeSort1.png

進一步擴展成更多的遞歸步驟:

![merge_sort_recursion.png](http://upload-images.jianshu.io/upload_images/3077991-03c40937f59045ae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
dac.png

Merge Sort

Merge Sort 采用的就是Divide-and-conquer 屎即,對于一個數(shù)組a[p....r]有以下三步:

  1. Divide 找到pr的中點q;
  2. Conquer 遞歸的對每次生成的子數(shù)組進行排序;
  3. Combine 把兩個排序好的子數(shù)組合并成一個排序好的數(shù)組事富。

舉一個具體例子:

? 對于一個數(shù)組 array[0..7] [14, 7, 3, 12, 9, 11, 6, 2] .

  • divide 階段,我們計算出來一個中值q=3
  • conquer 階段技俐,我們分別對兩個子數(shù)組array[0..3], [14, 7, 3, 12]array[4..7], [9, 11, 6, 2] 進行排序。當我們完成conquer 统台,兩個數(shù)組都是有序的分別是 [3, 7, 12, 14][2, 6, 9, 11],最后我們得到完整的數(shù)組[3, 7, 12, 14, 2, 6, 9, 11]
  • 最后在combine階段雕擂,我們合并(merge) 兩個數(shù)組,得到最終的有序數(shù)組[2, 3, 6, 7, 9, 11, 12, 14]

我們用圖形來演示一下這個過程:

![Uploading Merge-sort-example-300px_933644.gif . . .]

再來兩個動圖演示一下:

Merge-sort-example-300px.gif
Merge_sort_animation2.gif

Java 實現(xiàn)

public void mergeSort(int[] A, int start, int end, int[] temp) {
    if(start >= end) {
        return;
    }
    int left = start;
    int right = end;
    int mid = (start + end) / 2;
    
    mergeSort(A, start, mid, temp);
    mergeSort(A, mid + 1, end, temp);
    merge(A, start, mid, end, temp)
}

public void merge(int[] A, int start, int mid, int end, int[] temp) {
    int left = start;
    int right = mid + 1;
    int index = start;
    
    while(left <= mid && right <= end) {
        if(A[left] < A[right]) {
            temp[index++] = A[left++];
        } else {
            temp[index++] = A[right++];
        }
    }
  while(left <= mid) {
        temp[index++] = A[left++];
  } 
  while (right <= end) {
        temp[index++] = A[right++];
  }
  for(index = start; index <= end; index++) {
        A[index] = temp[index];
  }
}

LeetCode 衍生問題

算法前面說的比較清楚贱勃,直接說兩個比較難的問題:

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {val = x;}
}

解法1:

ListNode dummy = new ListNode(0);

public ListNode mergeKLists(ListNode[] list) {
    if(lists.length == 0) return null;
    int i = 0;
    int j = lists.length - 1;
    while( j != 0 ) {
        while(i < j) {
            lists[i] = mergeTwo(lists[i++], lists[j--]); 
        }
        i = 0;
    }
    return lists[0];
}

public ListNode mergeTwo(ListNode node1, ListNode node2) {
    ListNode head = dummy;
    while(node1 != null && node2 != null) {
        if(node1.val < node2.val) {
            head.next = node1;
            node1 = node1.next;
        }
        head = head.next;
    }
  if(node1 != null) {
        head.next = node1;
  }
  if(node2 != null) {
        head.next = node2;
  }
  return dummy.next;
}

解法2,我們借助java的優(yōu)先級隊列(PriorityQueue)來解這個問題:

    public ListNode mergeKLists(ListNode[] lists) {
        PriorityQueue<ListNode> heap = new PriorityQueue<>(new Comparator<ListNode>() {
            @Override
            public int compare(ListNode o1, ListNode o2) {
                return o1.val - o2.val;
            }
        });

        for(ListNode n : lists) {
            if(n != null) {
                heap.add(n);
            }
        }

        ListNode head = heap.peek();
        while(!heap.isEmpty()) {
            ListNode min = heap.poll();
            if (min.next != null) {
                heap.add(min.next);
            }
            min.next = heap.peek();
        }
        return head;
    }

優(yōu)先級隊列實現(xiàn)了一種通過堆排序來解決問題的方案井赌。

第二個問題 Merge Intervals:

Given a collection of intervals, merge all overlapping intervals.

For example,

Given [1,3],[2,6],[8,10],[15,18],

return [1,6],[8,10],[15,18].

數(shù)據(jù)結構如下:

 public class Interval {
        int start;
        int end;

        Interval() {start = 0; end = 0;}
        Interval(int s, int e) {start = s; end = e;}
    };

解法1:

 public List<Interval> merge(List<Interval> intervals) {
        if (intervals == null || intervals.size() <=1 ) return intervals;
        List<Interval> merged = new ArrayList<>();

        //對輸入進行一下排序
        Collections.sort(intervals, new Comparator<Interval>() {
            @Override
            public int compare(Interval o1, Interval o2) {
                if(o1.start != o2.start) {
                    return o1.start - o2.start;
                }
                return o1.end - o2.end;
            }
        });

        int startMin = intervals.get(0).start;
        int endMax = intervals.get(0).end;

        for (int i = 1; i < intervals.size(); i++) {
            int start = intervals.get(i).start;
            int end = intervals.get(i).end;

            if (start > endMax) {
                merged.add(new Interval(startMin, endMax));
                //完成一個節(jié)點的添加;
                startMin = start;
                endMax = end;
            } else {
                //吞掉一個節(jié)點贵扰;
                endMax = Math.max(end, endMax);
            }
        }
        merged.add(new Interval(startMin, endMax));
        return merged;
    }

解法2(原地排序仇穗,空間占用率低):

public List<Interval> merge(List<Interval> intervals) {
        if (intervals == null || intervals.size() < 2) {
            return intervals;
        }
        intervals.sort(new Comparator<Interval>() {
            @Override
            public int compare(Interval o1, Interval o2) {
                return o1.start - o2.start;
            }
        });
        int length = 1;
        for(int i = 1; i < intervals.size(); i++) {
            if(intervals.get(length - 1).end < intervals.get(i).start) {
                intervals.set(length++, intervals.get(i));
            } else {
                intervals.get(length - 1).end = Math.max(intervals.get(length - 1).end, intervals.get(i).end);
            }
        }
        return intervals.subList(0, length);
    }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市戚绕,隨后出現(xiàn)的幾起案子纹坐,更是在濱河造成了極大的恐慌,老刑警劉巖列肢,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恰画,死亡現(xiàn)場離奇詭異,居然都是意外死亡瓷马,警方通過查閱死者的電腦和手機拴还,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來欧聘,“玉大人片林,你說我怎么就攤上這事。” “怎么了费封?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵焕妙,是天一觀的道長。 經常有香客問我弓摘,道長焚鹊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任韧献,我火速辦了婚禮末患,結果婚禮上,老公的妹妹穿的比我還像新娘锤窑。我一直安慰自己璧针,他們只是感情好,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布渊啰。 她就那樣靜靜地躺著探橱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绘证。 梳的紋絲不亂的頭發(fā)上隧膏,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機與錄音迈窟,去河邊找鬼私植。 笑死忌栅,一個胖子當著我的面吹牛车酣,可吹牛的內容都是我干的。 我是一名探鬼主播索绪,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼湖员,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了瑞驱?” 一聲冷哼從身側響起娘摔,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎唤反,沒想到半個月后凳寺,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡彤侍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年肠缨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盏阶。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡晒奕,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情脑慧,我是刑警寧澤魄眉,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站闷袒,受9級特大地震影響坑律,放射性物質發(fā)生泄漏。R本人自食惡果不足惜囊骤,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一脾歇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧淘捡,春花似錦藕各、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至膘魄,卻和暖如春乌逐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背创葡。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工浙踢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灿渴。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓洛波,卻偏偏與公主長得像,于是被迫代替她去往敵國和親骚露。 傳聞我的和親對象是個殘疾皇子蹬挤,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內容