Leetcode新手学习之路

边学边记录,希望有所进步。

  1. 归并集
    核心思路:
    1)初始化,大家的老大都是自己;
    2)找老大;
    3)合并老大;

附547题朋友圈解法:

class Solution {
public:
    int FindAndUpdateFather(vector<int>& fathers, int i)
    {
        if (fathers[i] == i) {
            return i;
        }
        // key2, 找老大,边找边更新
        return (fathers[i] = FindAndUpdateFather(fathers, fathers[i]));
    }

    int findCircleNum(vector<vector<int>>& M) {
        int totalNum = M.size();
        vector<int> fathers(totalNum, 0);
        for (int i = 0; i < totalNum; i++) {
            fathers[i] = i; // 初始化,大家的老大都是自己
        }

        for (int i = 0; i < totalNum; i++) {
            for (int j = i + 1; j < totalNum; j++) {
                if (M[i][j] == 0) {
                    continue;
                }
                // key3,合并老大
                int fatheri = FindAndUpdateFather(fathers, i);
                int fatherj = FindAndUpdateFather(fathers, j);
                if (fatheri != fatherj) {
                    fathers[fatheri] = fatherj;
                }
            }
        }

        int count = 0;
        for (int i = 0; i < totalNum; i++) {
            if (fathers[i] == i) {
                count++;
            }
        }
        return count;
    }
};

附684. 冗余连接解法:

class Solution {
public:
    int FindRoot(vector<int>& roots, int idx)
    {
        if (roots[idx] == idx) {
            return idx;
        }
        return (roots[idx] = FindRoot(roots, roots[idx]));
    }
    vector<int> findRedundantConnection(vector<vector<int>>& edges) {
        int totalNum = edges.size();
        vector<int> roots(totalNum + 1, 0);
        for (int i = 0; i < totalNum; i++) {
            roots[i] = i;
        }
        int redundantIdx = 0;
        for (int i = 0; i < totalNum; i++) {
            int root0 = FindRoot(roots, edges[i][0]);
            int root1 = FindRoot(roots, edges[i][1]);
            if (root0 == root1) {
                redundantIdx = i; // record and try update the last redundant idx
            } else { // (root0 != root1) 
                roots[root0] = root1; // merge
            }
        }
        return edges[redundantIdx];
    }
};

附200. 岛屿数量解法:

class Solution {
public:
    int FindRoot(vector<int>& roots, int idx) {
        if (roots[idx] == idx) {
            return idx;
        }
        return (roots[idx] = FindRoot(roots, roots[idx]));
    }

    void TryMerge(vector<int>& roots, int i, int j, int& count) {
        int rooti = FindRoot(roots, i);
        int rootj = FindRoot(roots, j);
        if (rooti != rootj) {
            roots[rooti] = rootj;
            count--; // key1
        }
    }

    int numIslands(vector<vector<char>>& grid) {
        int hnum = grid.size();
        if (hnum == 0) {
            return 0;
        }
        int lnum = grid[0].size();
        vector<int> roots;
        int count = 0;
        for (int i = 0; i < hnum; i++) {
            for (int j = 0; j < lnum; j++) {
                if (grid[i][j] == '1') {
                    roots.push_back(i * lnum + j); // init
                    count++; // key1
                } else {
                    roots.push_back(-1);
                }
            }
        }
        for (int i = 0; i < hnum; i++) {
            for (int j = 0; j < lnum; j++) {
                if (grid[i][j] == '0') {
                    continue;
                }
                if ((i - 1 >= 0) && grid[i - 1][j] == '1') {
                    TryMerge(roots, (i - 1) * lnum + j, i * lnum + j, count); // key2
                }
                if ((i + 1 < hnum) && grid[i + 1][j] == '1') {
                    TryMerge(roots, (i + 1) * lnum + j, i * lnum + j, count); // key2
                }
                if ((j - 1 >= 0) && grid[i][j - 1] == '1') {
                    TryMerge(roots, i * lnum + j - 1, i * lnum + j, count); // key2
                }
                if ((j + 1 < lnum) && grid[i][j + 1] == '1') {
                    TryMerge(roots, i * lnum + j + 1, i * lnum + j, count); // key2
                }
            }
        }
        return count;
    }
};
  1. 句子相似性 II 解法思路:
    1). 引入unordered_map哈希表将字符串转换成数字(从0开始编号),每个字符串都有唯一的数字,每个数字的roots初始化成自己;
    2). 合并;
    3). 相似性判断;
    4). 注意哈希表的用法如:
    unordered_map mymap;
    mymap[it] = cnt;
    if (mymap.find(it) == mymap.end()) // 判断是否有该key
    mymap.at(pairs[i][0]) // 根据key找val
#include 
#include 

class Solution {
public:
    int FindRoot(vector<int>& roots, int idx)
    {
        if (roots[idx] == idx) {
            return idx;
        }
        return (roots[idx] = FindRoot(roots, roots[idx]));
    }

    bool areSentencesSimilarTwo(vector<string>& words1, vector<string>& words2, vector<vector<string>>& pairs)
    {
        unordered_map<string, int> mymap; // key1
        int hnum = pairs.size();
        int lnum = 0;
        if (hnum != 0) {
            lnum = pairs[0].size();
        }
        string it;
        int cnt = 0;
        vector<int> roots;
        // Init && string->int
        for (int i = 0; i < hnum; i++) {
            for (int j = 0; j < lnum; j++) {
                it = pairs[i][j];
                if (mymap.find(it) == mymap.end()) {
                    mymap[it] = cnt;
                    roots.push_back(cnt);
                    cnt++;
                }
            }
        }
        // merge
        for (int i = 0; i < hnum; i++) {
            int root1 = FindRoot(roots, mymap.at(pairs[i][0]));
            int root2 = FindRoot(roots, mymap.at(pairs[i][1]));
            if (root1 != root2) {
                roots[root1] = root2;
            }
        }
        if (words1.size() != words2.size()) {
            return false;
        }

        for (int i = 0; i < words1.size(); i++) {
            if (words1[i] == words2[i]) {
                continue;
            }
            if (mymap.find(words1[i]) == mymap.end() || mymap.find(words2[i]) == mymap.end()) {
                return false;
            }
            int root1 = FindRoot(roots, mymap.at(words1[i]));
            int root2 = FindRoot(roots, mymap.at(words2[i]));
            if (root1 != root2) {
                return false;
            }
        }
        return true;
    }
};
  1. 得分最高的路径 解法思路:
    1). 创建node结构体,其包含value和序号i,j,全部加入一个动态结构体数组a;
    2). 借用std::sort函数(需封装成mysort,否则编译不过)对a按大到小进行排序;
    3). 按i, j得到扁平化idx,并对roots进行初始化,每个序号的roots都是它自己;
    4). 将第一个元素和最后一个元素的扁平化idx(0,totalNum-1)加入集合set;
    5). 将a中的node的i,j -> idx按大到小逐个加入set,遍历i,j的上下左右是否已经在set中,如果是则merge对应的两个idx;更新out_value;
    6). 如果FindRoot(0) 和 FindRoot(totalNum-1)相同,则break;
typedef struct {
    int value;
    int i;
    int j;
} Node;

bool Cmp(const Node a, const Node b)
{
    return (a.value > b.value);
}

class Solution {
public:
    int FindRoot(vector<int>& roots, int idx)
    {
        if (roots[idx] == idx) {
            return idx;
        }
        return (roots[idx] = FindRoot(roots, roots[idx]));
    }

    void Merge(vector<int>& roots, int idx1, int idx2)
    {
        int root1 = FindRoot(roots, idx1);
        int root2 = FindRoot(roots, idx2);
        if (root1 == root2) {
            return;
        }
        roots[root1] = root2; 
    }
    void myprint(vector<int>& roots)
    {
        for (int i = 0; i < roots.size(); i++) {
            printf("roots[%d] = %d ", i, roots[i]);
        }
        printf("\n");
    }
    vector<Node> MySort(vector<Node>& a)
    {
        sort(a.begin(), a.end(), Cmp);
        return a;
    }
    int maximumMinimumPath(vector<vector<int>>& A)
    {
        int hnum = A.size();
        if (hnum == 0) {
            return 0;
        }
        int lnum = A[0].size();
        vector<Node> a;
        Node node;
        for (int i = 0; i < hnum; i++) {
            for (int j = 0; j < lnum; j++) {
                node.value = A[i][j];
                node.i = i;
                node.j = j;
                a.push_back(node);
            }
        }
        MySort(a);
        int totalNum = hnum * lnum;
        vector<int> roots;
        for (int i = 0; i < totalNum; i++) {
            roots.push_back(i); // init
        }
        set<int> s;
        int beginIdx = 0;
        int endIdx = 0;
        for (int i = 0; i < totalNum; i++) {
            if (a[i].i == 0 && a[i].j == 0) {
                beginIdx = i;
            }
            if (a[i].i == hnum - 1 && a[i].j == lnum - 1) {
                endIdx = i;
            }
        }
        s.insert(0);
        s.insert(totalNum - 1);
        int outValue = A[0][0] < A[hnum - 1][lnum - 1] ? A[0][0] : A[hnum - 1][lnum - 1];
        for (int i = 0; i < totalNum; i++) {
            int x = a[i].i;
            int y = a[i].j;
            if (x == 0 && y == 0) {
                continue;
            }
            if (x == hnum - 1 && y == lnum - 1) {
                continue;
            }
            if (outValue > a[i].value) {
                outValue = a[i].value;
            }
            s.insert(x * lnum + y);
            if ((x - 1 >= 0) && (s.find((x - 1) * lnum + y) != s.end())) {
                Merge(roots, x * lnum + y, (x - 1) * lnum + y);
            }
            if ((x + 1 < hnum) && (s.find((x + 1) * lnum + y) != s.end())) {
                Merge(roots, x * lnum + y, (x + 1) * lnum + y);
            }
            if ((y - 1 >= 0) && (s.find(x * lnum + y - 1) != s.end())) {
                Merge(roots, x * lnum + y, x * lnum + y - 1);
            }
            if ((y + 1 < lnum) && (s.find(x * lnum + y + 1) != s.end())) {
                Merge(roots, x * lnum + y, x * lnum + y + 1);
            }
            int rootBegin = FindRoot(roots, 0);
            int rootEnd = FindRoot(roots, totalNum - 1);
            if (rootBegin == rootEnd) {
                break;
            }
        }
        return outValue;
    }
};
  1. 最低成本联通所有城市 解法思路:与上一题有点类似
    1)以node形式保存每条connection,value就是连接成本,另外两个是数组下标(需要-1)h, l;
2)  按value从小到大进行排序;
3) 初始化并查集;此时并查集的总root数totalRootNum为N----关键;
4) 将node逐个取出,查看h,l的root是不是相同,若不同则merge并且totalRootNum--;
5) 若totalRootNum减少到1则break结束;
typedef struct {
    int value;
    int h;
    int l;
} Node;

bool Cmp(Node a, Node b)
{
    return a.value < b.value; // 从小到大
}

class Solution {
public:
    void MySort(vector<Node>& A)
    {
        sort(A.begin(), A.end(), Cmp);
    }

    int FindRoot(vector<int>& roots, int i)
    {
        if (roots[i] == i) {
            return i;
        }
        return (roots[i] = FindRoot(roots, roots[i]));
    }

    int minimumCost(int N, vector<vector<int>>& connections) {
        vector<int> roots;
        for (int i = 0; i < N; i++) {
            roots.push_back(i); // init
        }
        Node node;
        vector<Node> A;
        for (int i = 0; i < connections.size(); i++) {
            node.value = connections[i][2];
            node.h = connections[i][0] - 1;
            node.l = connections[i][1] - 1;
            A.push_back(node);
        }
        MySort(A);
        int totalRootNum = N;
        int totalValue = 0;
        for (int i = 0; i < A.size(); i++) {
            int root1 = FindRoot(roots, A[i].h);
            int root2 = FindRoot(roots, A[i].l);
            if (root1 == root2) {
                continue;
            }
            roots[root1] = root2; // merge
            totalRootNum--; // key: 每次merge后就少一个root,直到为1则退出;
            totalValue += A[i].value;
            if (totalRootNum <= 1) {
                break;
            }
        }
        if (totalRootNum <= 1) {
            return totalValue;
        }
        return -1;
    }
};
  1. 以图判树 解法:
class Solution {
public:
    int FindRoot(vector<int>& roots, int i)
    {
        if (roots[i] == i) {
            return i;
        }
        return (roots[i] = FindRoot(roots, roots[i]));
    }

    bool validTree(int n, vector<vector<int>>& edges) {
        vector<int> roots;
        for (int i = 0; i < n; i++) {
            roots.push_back(i); // init
        }
        int rootsNum = n;
        for (int i = 0; i < edges.size(); i++) {
            int root1 = FindRoot(roots, edges[i][0]);
            int root2 = FindRoot(roots, edges[i][1]);
            if (root1 == root2) {
                return false;
            }
            roots[root1] = root2; // merge
            rootsNum--; // key
        }
        if (rootsNum == 1) {
            return true;
        }
        return false;
    }
};
  1. 按字典序排列最小的等效字符串 解法
class Solution {
public:
    int Find(vector<int>& roots, int i)
    {
        if (roots[i] == i) {
            return i;
        }
        return (roots[i] = Find(roots, roots[i]));
    }

    string smallestEquivalentString(string A, string B, string S)
    {
        unordered_map<char, int> m;
        for (char i = 'a'; i <= 'z'; i++) {
            m[i] = i - 'a';
        }
        vector<int> roots;
        for (int i = 0; i <= ('z' - 'a'); i++) {
            roots.push_back(i);
        }
        for (int i = 0; i < A.size(); i++) {
            int root1 = Find(roots, m[A[i]]);
            int root2 = Find(roots, m[B[i]]);
            if (root1 == root2) {
                continue;
            }
            // merge
            if (root1 < root2) {
                roots[root2] = root1;
            } else {
                roots[root1] = root2;
            }
        }
        string out = "";
        for (int i = 0; i < S.size(); i++) {
            int rootIdx = Find(roots, m[S[i]]);
            out += (rootIdx + 'a');
        }
        return out;
    }
};
  1. 无向图中连通分量的数目 解法:
class Solution {
public:
    int Find(vector<int>& roots, int i)
    {
        if (roots[i] == i) {
            return i;
        }
        return (roots[i] = Find(roots, roots[i]));
    }

    int countComponents(int n, vector<vector<int>>& edges) {
        vector<int> roots;
        for (int i = 0; i < n; i++) {
            roots.push_back(i);
        }
        int totalNum = n;
        for (int i = 0; i < edges.size(); i++) {
            int root1 = Find(roots, edges[i][0]);
            int root2 = Find(roots, edges[i][1]);
            if (root1 == root2) {
                continue;
            }
            roots[root1] = root2;
            totalNum--;
        }
        return totalNum;
    }
};

你可能感兴趣的:(c++)