【Leetcode Sheet】Weekly Practice 4

Leetcode Test

849 到最近的人的最大距离(8.22)

给你一个数组 seats 表示一排座位,其中 seats[i] = 1 代表有人坐在第 i 个座位上,seats[i] = 0 代表座位 i 上是空的(下标从 0 开始)。

至少有一个空座位,且至少有一人已经坐在座位上。

亚历克斯希望坐在一个能够使他与离他最近的人之间的距离达到最大化的座位上。

返回他到离他最近的人的最大距离。

提示:

  • 2 <= seats.length <= 2 * 104
  • seats[i]01
  • 至少有一个 空座位
  • 至少有一个 座位上有人

【双指针,左右向中间遍历】

时间复杂度:O(n)

空间复杂度:O(1)

int maxDistToClosest(int* seats, int seatsSize){
    int n=seatsSize,dis=0;
    int left=0,right=n-1;
    //initialize
    
    while(left<n){
        if(seats[left]==1) break;
        left++;
    }
    dis=left;
    //handle left side,寻找左边第一个1
    
    while(right>=0){
        if(seats[right]==1) break;
        right--;
    }
    if(dis<n-1-right) dis=n-right-1;
    //handle right side,寻找右边第一个1
    
    if(right==left) return dis;
    //说明只有一个1,直接返回maxdis

    int lastleft=left;	//记录上一个1
    while(left<=right){
        if(seats[left]==1){
            int t=left-lastleft;
            dis=fmax(t/2,dis);	//求间隔的最大值
            lastleft=left;	//更新上一个1
        }
        left++;	//去下一个座位
    }
    return dis;
}

【双指针 + 贪心】官解

int maxDistToClosest(int* seats, int seatsSize) {
    int res = 0, l = 0;
    //寻找第一个1
    while (l < seatsSize && seats[l] == 0) {
        ++l;
    }
    //返回第一个1到左墙的距离
    res = fmax(res, l);
    //遍历
    while (l < seatsSize) {
        int r = l + 1;
        //寻找下一个1
        while (r < seatsSize && seats[r] == 0) {
            ++r;
        }
        //如果走到右墙(找不到下一个1)
        if (r == seatsSize) {
            res = fmax(res, r - l - 1);
        } 
        else {
            res = fmax(res, (r - l) / 2);
        }
        //更新left指针
        l = r;
    }
    return res;
}

1782 统计点对的数目(8.23)

给你一个无向图,无向图由整数 n ,表示图中节点的数目,和 edges 组成,其中 edges[i] = [ui, vi] 表示 uivi 之间有一条无向边。同时给你一个代表查询的整数数组 queries

j 个查询的答案是满足如下条件的点对 (a, b) 的数目:

  • a < b
  • cnt 是与 a 或者 b 相连的边的数目,且 cnt 严格大于 queries[j]

请你返回一个数组 answers ,其中 answers.length == queries.lengthanswers[j] 是第 j 个查询的答案。

请注意,图中可能会有 重复边

提示:

  • 2 <= n <= 2 * 104
  • 1 <= edges.length <= 105
  • 1 <= ui, vi <= n
  • ui != vi
  • 1 <= queries.length <= 20
  • 0 <= queries[j] < edges.length

【C++,Hash + binary search】容斥原理

class Solution {
public:
    vector<int> countPairs(int n, vector<vector<int>>& edges, vector<int>& queries) {
        vector<int> degree(n);
        //define the degrees of n nodes
        unordered_map<int,int> cnt;
        
        //calculate node degree and common edges' number
        for(auto edge: edges){
            //go thru all edges
            int x=edge[0]-1,y=edge[1]-1;
            if(x>y) swap(x,y);
            //ensure a<b
            degree[x]++;
            degree[y]++;
            cnt[x*n+y]++;
            //common edges recordance
        }

        vector<int> arr=degree;
        //define arr as degrees(copy degrees)
        vector<int> ans;
        sort(arr.begin(),arr.end());
        for(int bound: queries){
            //go thru all query
            int total=0;

            //binary-search method
            for(int i=0;i<n;i++){
                //upper_bound(begin,end,num):
                //从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。
                //通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
                int j=upper_bound(arr.begin()+i+1, arr.end(), bound-arr[i])-arr.begin();
                total+=n-j;
                //当前结点度数为arr[i],查找i之后,度数>(bound-arr[i])的第一个结点,编号为j
                //n-j为 符合i结点条件的 结点数
                //total进行依次叠加
            }

            //subtract common edges
            for(auto &[val,freq]: cnt){
                int x=val/n;
                int y=val%n;
                if(degree[x]+degree[y]>bound && degree[x]+degree[y]-freq<=bound){
                    //bound is current query number
                    total--;
                }
            }

            ans.emplace_back(total);//append an answer
        }
        return ans;
    }
};

1267 统计参与通信的服务器(8.24)

这里有一幅服务器分布图,服务器的位置标识在 m * n 的整数矩阵网格 grid 中,1 表示单元格上有服务器,0 表示没有。

如果两台服务器位于同一行或者同一列,我们就认为它们之间可以进行通信。

请你统计并返回能够与至少一台其他服务器进行通信的服务器的数量。

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m <= 250
  • 1 <= n <= 250
  • grid[i][j] == 0 or 1

【hash-table】记录每行每列,是否有2台以上的服务器

int countServers(int** grid, int gridSize, int* gridColSize){
    int m=gridSize,n=gridColSize[0];
    //return total number of communications
    
    //初始化hash表
    int *row=(int*)malloc(sizeof(int)*m);
    int *col=(int*)malloc(sizeof(int)*n);
    for(int i=0;i<m;i++){
        row[i]=0;
    }
    for(int i=0;i<n;i++){
        col[i]=0;
    }
    
    //统计是否有2台
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            if(grid[i][j]==1){
                row[i]++;
                col[j]++;
            }
        }
    }
    
    //遍历结果
    int result=0;
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            if(grid[i][j]==1 && (row[i]>1 || col[j]>1)){
                result++;
            }
        }
    }
    return result;
}

1448 统计二叉树中好节点的数目(8.25)

给你一棵根为 root 的二叉树,请你返回二叉树中好节点的数目。

「好节点」X 定义为:从根到该节点 X 所经过的节点中,没有任何节点的值大于 X 的值。

提示:

  • 二叉树中节点数目范围是 [1, 10^5]
  • 每个节点权值的范围是 [-10^4, 10^4]

【dfs】深度优先搜索,递归左、右子树

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

int dfs(struct TreeNode* root,int pathmax){
    if(root==NULL) return 0;    //不存在结点
    int result=0;               //计数
    if(root->val >= pathmax){   //如果根节点 >= 既往max
        result++;               //当前节点计入结果
        pathmax=root->val;      //更新max为当前节点
    }
    result+=dfs(root->left,pathmax) + dfs(root->right,pathmax);     //递归左子树和右子树
    return result;      //返回结果
}

int goodNodes(struct TreeNode* root){
    return dfs(root,INT_MIN);   //深度遍历
}

228 汇总区间(8.26)

给定一个 无重复元素有序 整数数组 nums

返回 *恰好覆盖数组中所有数字最小有序 区间范围列表* 。也就是说,nums 的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于 nums 的数字 x

列表中的每个区间范围 [a,b] 应该按如下格式输出:

  • "a->b" ,如果 a != b
  • "a" ,如果 a == b

提示:

  • 0 <= nums.length <= 20
  • -231 <= nums[i] <= 231 - 1
  • nums 中的所有值都 互不相同
  • nums 按升序排列

【双指针】start & end

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
char ** summaryRanges(int* nums, int numsSize, int* returnSize){
    int n=numsSize;
    char **result=malloc(sizeof(char*)*n);
    *returnSize=0;
    int i=0;
    while(i<n){
        int start=i;
        i++;
        while(i<n && nums[i]==nums[i-1]+1){
            i++;
        }
        int end=i-1;
        char *t=malloc(sizeof(char)*25);
        sprintf(t,"%d",nums[start]);
        if(start<end){
            sprintf(t+strlen(t),"->");
            sprintf(t+strlen(t),"%d",nums[end]);
            //sprintf的用法需要了解orz
        }
        result[(*returnSize)++]=t;
    }
    return result;
}

56 合并区间(8.27)

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间

提示:

  • 1 <= intervals.length <= 104
  • intervals[i].length == 2
  • 0 <= starti <= endi <= 104

【排序嵌套数组 + 双指针更新位置】

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */

//quick sort
int cmp(const void *a, const void *b){
    const int *pa = *(int **)a;
    const int *pb = *(int **)b;
    //定义指针
    if (pa[0] == pb[0]) {
        return pa[1] - pb[1];   //如果左侧相同,则比较右侧
    }
    return pa[0] - pb[0];   //如果左侧不同,直接按左侧排序
}

int** merge(int** intervals, int intervalsSize, int* intervalsColSize, int* returnSize, int** returnColumnSizes) {
    int m = intervalsSize, n = *intervalsColSize;
    //快排
    qsort(intervals, m, sizeof(intervals[0]), cmp);
    //left是第一个区间的左,right是第一个区间的右
    int i = 1, j = 0, cnt = 0, left = intervals[0][0], right = intervals[0][1];
    int **ans = (int **)malloc(m * sizeof(int *));
    *returnColumnSizes = (int *)malloc(m * sizeof(int *));
    
    //从第二个区间开始遍历
    while (i < m && j < m) {
        if (intervals[i][0] <= intervals[j][1]) {   //如果2区间的左 <= 1区间的右(两个区间有重合)
            if (intervals[i][1] >= right) {     //如果2区间的右 >= 1区间的右,eg【1,4】【2,5】
                right = intervals[i][1];    //更新right
                j = i;  //更新1区间
            }
        }
        else {      //2区间的左 > 1区间的右(两个区间不重合)
            (*returnColumnSizes)[cnt] = 2;              //区间长度为2
            ans[cnt] = (int *)malloc(2 * sizeof(int));  //append一个区间给ans
            ans[cnt][0] = left, ans[cnt][1] = right;    //设置数字
            cnt++;                                      //计数增加
            left = intervals[i][0], right = intervals[i][1];    //更新left和right
            j = i;                                      //更新j
        }
        i++;    //遍历下一个区间
    }
    //更新最后一个
    (*returnColumnSizes)[cnt] = 2;
    ans[cnt] = (int *)malloc(2 * sizeof(int));
    ans[cnt][0] = left, ans[cnt][1] = right;
    cnt++;
    *returnSize = cnt;
    return ans;
}

57 插入区间(8.28)

给你一个 无重叠的 *,*按照区间起始端点排序的区间列表。

在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。

提示:

  • 0 <= intervals.length <= 104
  • intervals[i].length == 2
  • 0 <= intervals[i][0] <= intervals[i][1] <= 105
  • intervals 根据 intervals[i][0]升序 排列
  • newInterval.length == 2
  • 0 <= newInterval[0] <= newInterval[1] <= 105
/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
int** insert(int** intervals, int intervalsSize, int* intervalsColSize, int* newInterval, int newIntervalSize, int* returnSize, int** returnColumnSizes){
    int m=intervalsSize,n=intervalsColSize[0];
    int left=newInterval[0],right=newInterval[1];
    *returnSize=0;
    bool place=0;
    int **ans=malloc(sizeof(int*)*(m+1));
    *returnColumnSizes=malloc(sizeof(int*)*(m+1));

    //循环所有区间
    for(int i=0;i<m;i++){
        int *t=intervals[i];    //定义当前区间
        if(t[0]>right){
            //当前区间左侧 大于 插入区间右侧
            if(place==0){   
                //如果没有被标记过
                //即append插入区间给ans
                int *temp=malloc(sizeof(int)*2);    //给temp赋值
                temp[0]=left;
                temp[1]=right;
                (*returnColumnSizes)[*returnSize]=2;
                ans[(*returnSize)++]=temp;
                place=1;    //标志已经放置
            }
            //append当前区间给ans
            int *temp=malloc(sizeof(int)*2);
            memcpy(temp,t,sizeof(int)*2);
            (*returnColumnSizes)[*returnSize]=2;
            ans[(*returnSize)++]=temp;
        }
        else if(t[1]<left){
            //当前区间右侧 小于 插入区间左侧
            //即append当前区间给ans
            int *temp=malloc(sizeof(int)*2);
            memcpy(temp,t,sizeof(int)*2);   //将t赋值给temp
            (*returnColumnSizes)[*returnSize]=2;
            ans[(*returnSize)++]=temp;
        }
        else{
            //有交集
            //修改left为两个区间的最小左侧,right为两个区间的最大右侧
            left=fmin(left,t[0]);
            right=fmax(right,t[1]);
        }
    }
    if(place==0){
        //没有被设置过放置,即插入区间位于最右侧的最大区间
        int *temp=malloc(sizeof(int)*2);
        temp[0]=left;
        temp[1]=right;
        (*returnColumnSizes)[*returnSize]=2;
        ans[(*returnSize)++]=temp;
    }
    return ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MorleyOlsen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值