Leetcode257周周赛

  • 1995 .统计特殊四元组(easy)

  • 5864.游戏中的弱角色 (middle)

  • 1997.访问完所有房间的第一天(middle)

  • 1998.数组的最大公因数排序(hard)

5864. 游戏中弱角色的数量

你正在参加一个多角色游戏,每个角色都有两个主要属性:攻击防御 。给你一个二维整数数组 properties ,其中 properties[i] = [attacki, defensei] 表示游戏中第 i 个角色的属性。

如果存在一个其他角色的攻击和防御等级 都严格高于 该角色的攻击和防御等级,则认为该角色为 弱角色 。更正式地,如果认为角色 i 弱于 存在的另一个角色 j ,那么 attackj > attackidefensej > defensei

返回 弱角色 的数量。

示例 1:

输入:properties = [[5,5],[6,3],[3,6]]
输出:0
解释:不存在攻击和防御都严格高于其他角色的角色。

思路分析

  • 题目涉及到数值比较,故先排序,排序顺序为攻击从大到小,同等攻击值从小到大。
  • 弱角色存在于右边,在遍历过程中,右边角色攻击均小于或等于左边,设maxProperty为defense最大的非弱角色,de和at为其防御值和攻击值,这样可以保证在遍历过程中,右边所有弱角色防御和攻击均小于maxProperty。
  • 遍历时maxProperty的更新条件如下:

i f    P r o p e r t i e s [ i ]    i s    n o t    a    w e a k    r o l e d e = P r o p e r t i e s [ i ] [ 1 ] a t = P r o p e r t i e s [ i ] [ 0 ] if \;Properties[i] \;is \;not \;a \;weak \;role\\ de = Properties[i][1]\\ at = Properties[i][0] ifProperties[i]isnotaweakrolede=Properties[i][1]at=Properties[i][0]

代码实现

int cmp(int **a,int **b){
    if(a[0][0]!=b[0][0]){
        return b[0][0]-a[0][0];
    }
    return a[0][1]-b[0][1];
}
int numberOfWeakCharacters(int** properties, int propertiesSize, int* propertiesColSize){
    qsort(properties,propertiesSize,sizeof(properties[0]),cmp);
    int at=properties[0][0];
    int de=properties[0][1];
    int count=0;
    for (int i=1; i<propertiesSize; i++) {
        if (de > properties[i][1]) {
            if (at > properties[i][0]) {
                count++;
            }else{
                de = properties[i][1];
                at = properties[i][0];
            }
        } else {
            de = properties[i][1];
            at = properties[i][0];
        }
    }
    return count;
}

运行效果

在这里插入图片描述

1997. 访问完所有房间的第一天

你需要访问 n 个房间,房间从 0n - 1 编号。同时,每一天都有一个日期编号,从 0 开始,依天数递增。你每天都会访问一个房间。

最开始的第 0 天,你访问 0 号房间。给你一个长度为 n下标从 0 开始 的数组 nextVisit 。在接下来的几天中,你访问房间的 次序 将根据下面的 规则 决定:

  • 假设某一天,你访问 i 号房间。
  • 如果算上本次访问,访问 i 号房间的次数为 奇数 ,那么 第二天 需要访问 nextVisit[i] 所指定的房间,其中 0 <= nextVisit[i] <= i
  • 如果算上本次访问,访问 i 号房间的次数为 偶数 ,那么 第二天 需要访问 (i + 1) mod n 号房间。

请返回你访问完所有房间的第一天的日期编号。题目数据保证总是存在这样的一天。由于答案可能很大,返回对 109 + 7 取余后的结果。

示例 1:

输入:nextVisit = [0,0]
输出:2
解释:
- 第 0 天,你访问房间 0 。访问 0 号房间的总次数为 1 ,次数为奇数。
  下一天你需要访问房间的编号是 nextVisit[0] = 0
- 第 1 天,你访问房间 0 。访问 0 号房间的总次数为 2 ,次数为偶数。
  下一天你需要访问房间的编号是 (0 + 1) mod 2 = 1
- 第 2 天,你访问房间 1 。这是你第一次完成访问所有房间的那天。

思路分析

  • 动态规划,dp[i]表示从0房间到第i个房间所需要的时间。

  • 根据0<=nextVisit[i]<=i可以判定访问次数为基数时必回退到小于等于i的某个点,为偶数时才会 +1,故从dp[i+1]=dp[i]+(dp[i]-dp[nextVisit[i]])+2

  • 公式如下:
    d p [ i ] = 2 ∗ d p [ i − 1 ] − d p [ n e x t V i s i t [ i − 1 ] ] + 2 dp[i] = 2*dp[i-1]-dp[nextVisit[i-1]]+2 dp[i]=2dp[i1]dp[nextVisit[i1]]+2

代码

int firstDayBeenInAllRooms(int* nextVisit, int nextVisitSize){
    long* dp = malloc(nextVisitSize*sizeof(long));
    dp[0] = 0;
    int mod = (int)1e9+7;
    for(int i = 1;i<nextVisitSize;i++){
        dp[i] = (2*dp[i-1]-dp[nextVisit[i-1]]+2+mod)%mod;
    }
    return (int)dp[nextVisitSize-1];
}

结果

在这里插入图片描述

1998.数组的最大公因数排序

给你一个整数数组 nums ,你可以在 nums 上执行下述操作 任意次

  • 如果 gcd(nums[i], nums[j]) > 1 ,交换 nums[i]nums[j] 的位置。其中 gcd(nums[i], nums[j])nums[i]nums[j] 的最大公因数。

如果能使用上述交换方式将 nums非递减顺序 排列,返回 true ;否则,返回 false

示例 1:

输入:nums = [7,21,3]
输出:true
解释:可以执行下述操作完成对 [7,21,3] 的排序:
- 交换 7 和 21 因为 gcd(7,21) = 7 。nums = [21,7,3]
- 交换 21 和 3 因为 gcd(21,3) = 3 。nums = [3,7,21]

思路

  • 拥有相同公因数的数可以相互交换位置,a与b可以交换,a与c可以交换,则a,b,c可以互相交换。

  • 将所有可以相互交换位置的数字放入同一个集合中,以链式结构存放,若两个数可以相互交换,则a的链尾等于b的链尾。

    在这里插入图片描述

  • nums[i]<=105,故用长度为105+1的数组p作为链接数组,p[i]表示i的下一个节点。

  • 将原数组排序,比较新数组与原数组nums[i]与nums[i]是否可以进行交换,若不能交换则返回false.

代码

//找到尾部节点并更新前面节点指向的节点
int find(int x,int* p){
    if(x!=p[x]){
        p[x]=find(p[x],p);
    }
    return p[x];
}
//合并,将新数添加到之前的集合中
void merge(int x,int y,int* p){
    int a = find(x,p);
    int b = find(y,p);
    if(a==b){
        return;
    }
    p[a]=b;
}
int cmp(int* a,int* b){
    return *a-*b;
}
bool gcdSort(int* nums, int numsSize){
    int N = 1e5+1;
    int* p=malloc(N*sizeof(int));
    for(int i=0;i<N;i++){
        p[i]=i;
    }
    //分解质因数
    for(int i=0;i<numsSize;i++){
        int k = nums[i];
        for(int j=2;j<=k/j;j++){
            bool flag = false;
            while(k%j==0){
                k=k/j;
                flag=true;
            }
            if(flag){
                merge(nums[i],j,p);
            }
        }
        if(k>1){
            merge(nums[i],k,p);
        }
    }
    //tmp数组存储原来的数据
    int* tmp = malloc(numsSize*sizeof(int));
    for(int i=0;i<numsSize;i++){
        tmp[i]=nums[i];
    }
    //排序
    qsort(nums,numsSize,sizeof(int),cmp);
    for(int i=0;i<numsSize;i++){
        if(nums[i] == tmp[i]){
            continue;
        }
        if(find(nums[i],p) != find(tmp[i],p)){
            return false;
        }
    }
    return true;
}

结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值