1. 程式人生 > >演算法設計與分析第二週練習

演算法設計與分析第二週練習

目錄

Course Schedule(拓撲) Kth Largest Element in an Array(分治演算法)

Kth Largest Element in an Array

題目

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

Example

Input: [3,2,1,5,6,4] and k = 2
Output: 5

Example

Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4

分析

這周剛好講了分治演算法,我們就拿這個簡單的求第k大的數來練練手,其實這題也可以用堆疊的方法去完成,不過我們還是需要熟悉一下分治演算法。由於陣列是隨機的,所以演算法的時間複雜度是有提高的,具體演算法的過程:

  • 是找一個數組元素,將陣列中比這個元素大的元素放到這個元素的前面,比這個元素小的元素放到這個元素的後面。
  • 如果這個元素的下標剛好等於k-1,則返回;如果下標大於k-1,則在前面的元素用同樣的辦法找;如果下標小於k-1,則在後面的元素用同樣的辦法找。

這樣不斷的把這個問題一分為二,不斷減少問題的規模,而且問題的本質沒有發生變化。 以第一個例子為例,具體的過程如下: 3作為標誌的數,5,6,4,3,2,1 然後k=2,目標數在左邊 5作為標誌數,6,5,4 這樣答案便得出。

原始碼

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        int r = nums.size() - 1, left = 0, right = r, l = left;

        while(1) {
            l = left + 1;
            r = right;
            //cout << "b" << tag << l << r << endl;
while(l <= r) { if(nums[l] <= nums[left]&&nums[r] > nums[left]) { int temp = nums[l]; nums[l] = nums[r]; nums[r] = temp; l++; r--; } if(nums[r] <= nums[left]) { r--; } if(nums[l] >= nums[left]) { l++; } } int temp = nums[left]; nums[left] = nums[r]; nums[r] = temp; int result = r; if((k == result + 1)) { return nums[result]; } else if(result < k - 1) { left = result + 1; } else { right = result - 1; } //cout << "1" << tag << l << r << endl; } } };

Course Schedule(拓撲)

題目

There are a total of n courses you have to take, labeled from 0 to n-1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?

Example

Input: 2, [[1,0]] 
Output: true
Explanation: There are a total of 2 courses to take. 
             To take course 1 you should have finished course 0. So it is possible.

Example

Input: 2, [[1,0],[0,1]]
Output: false
Explanation: There are a total of 2 courses to take. 
             To take course 1 you should have finished course 0, and to take course 0 you should
             also have finished course 1. So it is impossible.

分析

這題是圖論方面的題目,在leetcode只有那麼僅僅的幾道題。同時這也是Topological Sort的代表性題目,通過規定完成某個事件之前必須要完成某些特點的事件,也就是事件之間有明確的先後順序,這些事件完成的順序不一定只有一種,但必須滿足某些事件的特定的順序,這樣所形成的序列被稱為拓撲序列,選課之前完成某些先導課程這樣便是典型的例子。 題目要求我們判斷所給出的序列是否為拓撲序列,根據拓撲序列的特徵:事件構成的圖是無環的。我們得出一下判斷的演算法。

  • 圖的每個點都對應著入度和出度,在初始情況下,只有那些起點的入度為0,一個拓撲序列可以有多個起點。
  • 先計算每個點的入度。
  • 從起點開始遍歷,遍歷到入度就少1,將入度為0的點push進棧中。
  • 最後如果某個點入度不為0,那麼就證明序列有環。

原始碼

class Solution {
public:
    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<int> in(numCourses,0);
        queue<int> empty;
        vector<vector<int> > temp(numCourses, vector<int>(0));
        //建立圖,vector的二維陣列
        for(auto a : prerequisites) {
            temp[a.second].push_back(a.first);
            in[a.first]++;
        }

        //將入度為0的點存進佇列裡面
        for(int i = 0; i < numCourses; i++) {
            if(in[i] == 0) {
                empty.push(i);
            } 
        }
        //入度為0的點作為開始的點,檢查是否有環
        while(!empty.empty()) {
            int frist_point = empty.front();
            empty.pop();
            for(auto a : temp[frist_point]) {
                in[a]--;
                if(in[a] == 0) {
                    empty.push(a);
                }
            }
        }
        for(int i = 0; i < numCourses; i++) {
            if(in[i] != 0) {
                return false;
            }
        }
        return true;
    }
};