# 算法设计与分析第二周练习

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

# 题目

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-1，这个堆是有序的，当堆没满的时候，将元素直接插入堆中，当堆满后，我们可以有取舍进行操作，当遍历的元素小于堆的最小元素（堆的第一个元素），我们不需要处理；当遍历的元素大于堆顶元素时，pop堆顶元素，将元素插入到堆中。最后堆顶的元素即为第k大的元素。
• 第二个思路就是运用分治算法；具体算法的过程:

• 是找一个数组元素，将数组中比这个元素大的元素放到这个元素的前面，比这个元素小的元素放到这个元素的后面。
• 如果这个元素的下标刚好等于k-1，则返回；如果下标大于k-1，则在前面的元素用同样的办法找；如果下标小于k-1，则在后面的元素用同样的办法找。

这样不断的把这个问题一分为二，不断减少问题的规模，而且问题的本质没有发生变化。

## 源码

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.

## 分析

• 图的每个点都对应着入度和出度，在初始情况下，只有那些起点的入度为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;
}
};