Leetcode 第 206 场周赛

  1. 二进制矩阵中的特殊位置

给你一个大小为 rows x cols 的矩阵 mat,其中 mat[i][j] 是 0 或 1,请返回 矩阵 mat 中特殊位置的数目 。

特殊位置 定义:如果 mat[i][j] == 1 并且第 i 行和第 j 列中的所有其他元素均为 0(行和列的下标均 从 0 开始 ),则位置 (i, j) 被称为特殊位置。

class Solution {
     
public:
    bool check(vector<vector<int>>& mat,int x,int y) {
     
        int n = mat.size(),m = mat[0].size();
        for(int i = 0;i < n;i++) {
     
            if(i == x) continue;
            if(mat[i][y] == 1) return false;
        }
        for(int i = 0;i < m;i++) {
     
            if(i == y) continue;
            if(mat[x][i] == 1) return false;
        }
        return true;
    }
    int numSpecial(vector<vector<int>>& mat) {
     
        int ans = 0;
        int n = mat.size(),m = mat[0].size();
        for(int i = 0;i < n;i++) {
     
            for(int j = 0;j < m;j++) {
     
                if(mat[i][j] == 1) {
     
                    if(check(mat,i,j)) ans++;
                }
            }
        }
        return ans;
    }
};
  1. 统计不开心的朋友

给你一份 n 位朋友的亲近程度列表,其中 n 总是 偶数 。

对每位朋友 i,preferences[i] 包含一份 按亲近程度从高到低排列 的朋友列表。换句话说,排在列表前面的朋友与 i 的亲近程度比排在列表后面的朋友更高。每个列表中的朋友均以 0 到 n-1 之间的整数表示。

所有的朋友被分成几对,配对情况以列表 pairs 给出,其中 pairs[i] = [xi, yi] 表示 xi 与 yi 配对,且 yi 与 xi 配对。

但是,这样的配对情况可能会是其中部分朋友感到不开心。在 x 与 y 配对且 u 与 v 配对的情况下,如果同时满足下述两个条件,x 就会不开心:

x 与 u 的亲近程度胜过 x 与 y,且
u 与 x 的亲近程度胜过 u 与 v
返回 不开心的朋友的数目 。

思路:
直接模拟

class Solution {
     
public:
    int a[505][505];
    int vis[505];
    bool check(int x,int y,int u,int v) {
     
        if(a[x][u] > a[x][y] && a[u][x] > a[u][v]) return true;
        return false;
    }
    int unhappyFriends(int n, vector<vector<int>>& preferences, vector<vector<int>>& pairs) {
     
        memset(a,0,sizeof(a));
        memset(vis,0,sizeof(vis));
        int m = n - 1;
        for(int i = 0;i < n;i++) {
     
            for(int j = 0;j < m;j++) {
     
                a[i][preferences[i][j]] = m - j;
            }
        }
        int ans = 0;
        for(int i = 0;i < pairs.size();i++) {
     
            for(int j = 0;j < pairs.size();j++) {
     
                if(i == j) continue;
                int x = pairs[i][0],y = pairs[i][1];
                int u = pairs[j][0],v = pairs[j][1];
                if(check(x,y,u,v) || check(x,y,v,u)) vis[x] = 1;
                if(check(y,x,u,v) || check(y,x,v,u)) vis[y] = 1;
            }
        }
        for(int i = 0;i < n;i++) if(vis[i]) ans++;
        return ans;
    }
};
  1. 连接所有点的最小费用

给你一个points 数组,表示 2D 平面上的一些点,其中 points[i] = [xi, yi] 。

连接点 [xi, yi] 和点 [xj, yj] 的费用为它们之间的 曼哈顿距离 :|xi - xj| + |yi - yj| ,其中 |val| 表示 val 的绝对值。

请你返回将所有点连接的最小总费用。只有任意两点之间 有且仅有 一条简单路径时,才认为所有点都已连接。

思路:
最小生成树裸题

struct Edge {
     
    int x,y,d;
    bool operator < (const Edge&rhs) const {
     
        return d < rhs.d; 
    }
};
class Solution {
     
public:
    int fa[1005];
    vector<Edge>vec;
    int dis(int x1,int y1,int x2,int y2) {
     
        return abs(x1 - x2) + abs(y1 - y2);
    }
    int findset(int x) {
     
        if(fa[x] == x) return x;
        return fa[x] = findset(fa[x]);
    }
    int minCostConnectPoints(vector<vector<int>>& points) {
     
        int n = points.size();
        for(int i = 0;i < points.size();i++) fa[i] = i;
        for(int i = 0;i < points.size();i++) {
     
            for(int j = i + 1;j < points.size();j++) {
     
                int x1 = points[i][0],y1 = points[i][1];
                int x2 = points[j][0],y2 = points[j][1];
                int d = dis(x1,y1,x2,y2);
                vec.push_back({
     i,j,d});
            }
        }
        sort(vec.begin(),vec.end());
        int cnt = 0;
        int ans = 0;
        for(int i = 0;i < vec.size();i++) {
     
            int x = vec[i].x,y = vec[i].y,d = vec[i].d;
            int rx = findset(x),ry = findset(y);
            if(rx != ry) {
     
                cnt++;
                fa[rx] = ry;
                ans += vec[i].d;
            }
            if(cnt >= n - 1) break;
        }
        return ans;
    }
};
  1. 检查字符串是否可以通过排序子字符串得到另一个字符串

给你两个字符串 s 和 t ,请你通过若干次以下操作将字符串 s 转化成字符串 t :

选择 s 中一个 非空 子字符串并将它包含的字符就地 升序 排序。
比方说,对下划线所示的子字符串进行操作可以由 “14234” 得到 “12344” 。

如果可以将字符串 s 变成 t ,返回 true 。否则,返回 false 。

一个 子字符串 定义为一个字符串中连续的若干字符。

思路:
比赛的时候没写出来嘤嘤嘤。
比赛的时候想的很复杂,用了线段树维护,后来感觉和逆序对有关(因为相同数字连线,看起来就像是二维偏序),但其实就是个思维题。

题目是选择一段,将其排序,不过并没有可行的数据结构维护这个过程。
可以简化这个操作,其实就是选择相邻两个数A,B,如果A>B那么就可以交换,那么只要A前面没有数字比A小,A就可以交换到前面任意位置。

那么考虑 t t t数列中第一个数字在 s s s数列中出现的位置,只要这个位置前面没有出现过比他小的数,那么就说明那个数可以移动过来,然后删掉这个数。

对于 t t t数列中后面的数字也是相同的考虑,这就类似划分子问题了,你把已经匹配的数删掉,那么每次相当于都是考虑要把 s s s数组中那个对应 t t t数组最前面的数移到最前面来。

class Solution {
     
public:
    queue<int>q[20];
    bool isTransformable(string s, string t) {
     
        int n = s.size();
        for(int i = 0;i < n;i++) {
     
            q[s[i] - '0'].push(i);
        }
        for(int i = 0;i < n;i++) {
     
            //如果没有数了肯定变不了
            if(q[t[i] - '0'].empty()) return false;

            //每个数可以往前移动到任意位置,直到前面所有数都比他小
            //同理也可以往后移动到任意位置,直到后面所有数都比他大
            for(int j = 0;j < t[i] - '0';j++) {
     
                if(!q[j].empty() && q[j].front() < q[t[i] - '0'].front()) return false;
            }
            q[t[i] - '0'].pop();

        }
        return true;
    }
};

你可能感兴趣的:(#,leetcode)