[LEECODE]算法进阶自练习9-10 图&堆和排序
9.图
中等
- 岛屿数量 leetcode 200 BFS解法:
int numIslands(vector<vector<char>>& grid) {
int count = 0, m = grid.size();
if(m == 0) return 0;
int n = grid[0].size();
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
if(grid[i][j] == '1'){
grid[i][j] = '0';
count++;
queue<pair<int,int>> que;
que.push({i,j});
while(!que.empty()){
auto t = que.front();
que.pop();
int r = t.first, c = t.second;
if(r-1>=0 && grid[r-1][c] == '1') {
grid[r-1][c] = '0';
que.push({r-1,c});
}
if(r+1<m && grid[r+1][c] == '1') {
grid[r+1][c] = '0';
que.push({r+1,c});
}
if(c-1>=0 && grid[r][c-1] == '1') {
grid[r][c-1] = '0';
que.push({r,c-1});
}
if(c+1<n && grid[r][c+1] == '1') {
grid[r][c+1] = '0';
que.push({r,c+1});
}
}
}
}
}
return count;
}
DFS解法:
void disIsland(vector<vector<char>>& grid, int i, int j){
int m = grid.size(), n = grid[0].size();
grid[i][j] = '0';
if(i-1 >= 0 && grid[i-1][j] == '1') disIsland(grid, i-1, j);
if(i+1 < m && grid[i+1][j] == '1') disIsland(grid, i+1, j);
if(j-1 >= 0 && grid[i][j-1] == '1') disIsland(grid, i, j-1);
if(j+1 < n && grid[i][j+1] == '1') disIsland(grid, i, j+1);
}
int numIslands(vector<vector<char>>& grid) {
int count = 0, m = grid.size();
if(m == 0) return 0;
int n = grid[0].size();
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
if(grid[i][j] == '1'){
disIsland(grid, i, j);
count++;
}
}
}
return count;
}
并查集解法:
class UnionFind{
private:
vector<int> rank;
vector<int> parent;
int count;
public:
UnionFind(vector<vector<char>>& grid){
count = 0;
int m = grid.size(), n = grid[0].size();
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
if(grid[i][j] == '1'){
parent.push_back(i*n+j);
++count;
}
else{
parent.push_back(-1);
}
rank.push_back(0);
}
}
}
int find(int i){
if(i != parent[i]) parent[i] = find(parent[i]);
return parent[i];
}
void punion(int x, int y){
int rx = find(x), ry = find(y);
if(rx != ry){
if(rank[rx] < rank[ry]) swap(rank[rx],rank[ry]);
parent[rx] = parent[ry];
if(rank[rx] == rank[ry]) rank[rx] += 1;
--count;
}
}
int getCount() const { return count; }
};
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
int m = grid.size();
if(!m) return 0;
int n = grid[0].size();
UnionFind uf(grid);
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
if(grid[i][j] == '1'){
grid[i][j] = '0';
if(i-1 >= 0 && grid[i-1][j] == '1') uf.punion(i*n+j,(i-1)*n+j);
if(i+1 < m && grid[i+1][j] == '1') uf.punion(i*n+j,(i+1)*n+j);
if(j-1 >= 0 && grid[i][j-1] == '1') uf.punion(i*n+j, i*n+j-1);
if(j+1 < n && grid[i][j+1] == '1') uf.punion(i*n+j, i*n+j+1);
}
}
}
return uf.getCount();
}
};
- 课程表II leetcode 210 DFS解法:
class Solution {
vector<vector<int>> edges;
vector<int> visited;
vector<int> result;
bool valid = true; // 是否有环
public:
void dfs(int i){
// 标记为搜索中
visited[i] = 1;
// 查找所有边
for(int v: edges[i]){
if(visited[v] == 0){
dfs(v);
if(!valid){
return;
}
}
else if(visited[v] == 1){
valid = false;
return;
}
}
visited[i] = 2;
result.push_back(i);
}
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
edges.resize(numCourses);
visited.resize(numCourses);
for(const auto& info:prerequisites){
edges[info[1]].push_back(info[0]);
}
for(int i=0; i<numCourses && valid; i++){
if(!visited[i]){
dfs(i);
}
}
if(!valid){
return {};
}
reverse(result.begin(),result.end());
return result;
}
};
BFS解法:
class Solution {
vector<vector<int>> edges;
vector<int> indeg;
vector<int> result;
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
edges.resize(numCourses);
indeg.resize(numCourses);
for(const auto& info:prerequisites){
edges[info[1]].push_back(info[0]);
++indeg[info[0]];
}
queue<int> q;
// 没有被依赖的课程可以先修
for(int i=0; i<numCourses; i++){
if(indeg[i] == 0){
q.push(i);
}
}
while(!q.empty()){
int u = q.front();
q.pop();
result.push_back(u);
for(int v: edges[u]){
--indeg[v];
if(indeg[v] == 0){
q.push(v);
}
}
}
if(result.size() != numCourses){
return {};
}
return result;
}
};
10.堆和排序
简单
- 数据流中第K大元素 leetcode 703 使用multiset解法:
class KthLargest {
multiset<int> s;
int K;
public:
KthLargest(int k, vector<int>& nums) {
for(int num : nums){
s.insert(num);
if(s.size() > k) s.erase(s.begin());
}
K = k;
}
int add(int val) {
s.insert(val);
if(s.size() > K) s.erase(s.begin());
return *s.begin();
}
};
使用priority_queue解法:
class KthLargest {
priority_queue<int, vector<int>, greater<int>> pq;
int K;
public:
KthLargest(int k, vector<int>& nums) {
for(int num : nums){
pq.push(num);
if(pq.size() > k) pq.pop();
}
K = k;
}
int add(int val) {
pq.push(val);
if(pq.size() > K) pq.pop();
return pq.top();
}
};
中等
- 数据流的中位数 leetcode 295 基础排序解法,不能AC:
class MedianFinder {
public:
vector<double> vec;
/** initialize your data structure here. */
MedianFinder() {
}
void addNum(int num) {
vec.emplace_back(num);
}
double findMedian() {
sort(vec.begin(),vec.end());
int vsize = vec.size();
return (double) (vsize&1 ? vec[vsize/2] : (vec[vsize/2] + vec[vsize/2-1])/2);
}
};
二分查找插入排序,不能AC:
class MedianFinder {
public:
vector<double> vec;
/** initialize your data structure here. */
MedianFinder() {
}
void addNum(int num) {
if(vec.empty()){
vec.emplace_back(num);
}
else{
vec.insert(lower_bound(vec.begin(),vec.end(), num),num);
}
}
double findMedian() {
sort(vec.begin(),vec.end());
int vsize = vec.size();
return (double) (vsize&1 ? vec[vsize/2] : (vec[vsize/2] + vec[vsize/2-1])/2);
}
};
priority_queue两个堆一大一小方法:
class MedianFinder {
public:
priority_queue<int> prevH; // 最大堆
priority_queue<int,vector<int>,greater<int>> nextH; // 最小堆
/** initialize your data structure here. */
MedianFinder() {
}
void addNum(int num) {
prevH.push(num);
nextH.push(prevH.top());
prevH.pop();
if(prevH.size() < nextH.size()){
prevH.push(nextH.top());
nextH.pop();
}
}
double findMedian() {
return (double)(prevH.size()>nextH.size() ? prevH.top() : (double)(prevH.top() + nextH.top())/2); // 后面的double一定要有不然会丢精度
}
};
multiset+双指针解法:
class MedianFinder {
public:
multiset<int> st;
multiset<int>::iterator left, right;
/** initialize your data structure here. */
MedianFinder():left(st.end()),right(st.end()) {
}
void addNum(int num) {
int ssize = st.size();
st.insert(num);
if(!ssize){ // 原先size==0
left = right = st.begin();
return;
}
if(ssize&1){
// 奇数个数
(num < *left) ? left-- : right++;
}
else{
// 偶数个数
if(*left < num && *right > num){
left++; right--;
}else if(*right <= num){
left++;
}else{
left = --right; // 注意这里 equal_range
}
}
}
double findMedian() {
return (double)(*left + *right)/2;
}
};