力扣第252场周赛题解

声明:因为是先在注释里面写了思路,要看思路的话看注释吧。就不搬出来了
第一题、三除数
链接:https://leetcode-cn.com/problems/three-divisors/
思路:

​ 直接暴力循环,查找正除数的个数就可以了

代码实现:
class Solution {
public:
    bool isThree(int n) {
        int cur = 0 ;
        for(int i = 1 ; i <= n ; ++ i)
            cur += n % i == 0 ? 1 : 0 ;
        return cur == 3 ;
    }
};
第二题、你可以工作的最大周数
链接:https://leetcode-cn.com/problems/maximum-number-of-weeks-for-which-you-can-work/
思路:

​ 根据每周切换项目的规则,可以借助阶段任务最多的项目完成多次切换。推导结果看代码注释

代码实现:
class Solution {
public:
    long long numberOfWeeks(vector<int>& w) {
        sort(w.begin() , w.end()) ;
        long long sum = 0 , cur = 0 ;
        for(auto &i : w)
            sum += i ;  //计算所有数的总和
        cur = sum - w.back() ;  //计算除了最大的数,其他数的和
        if(cur < w.back())  //这是y + z + ... < x 的情况
            return cur * 2 + 1 ;
        return sum ;    //否则返回sum即可
    }
};

/*
x y z ....

x是最大的,判断是不是比其他的加起来都大

y + z + ... <= x 则最大结果为:(y + z) * 2 + 1
切换方法:一个x项目,一个其他项目,来回切换,最后可以再参与一次x项目

y + z + ... >= x 则最大结果为sum
切换方法,每个项目做一周,循环直到y + z + ... = x为止,然后一次其他项目,一次x项目来回切换直到所有项目完成
*/
第三题、收集足够苹果的最小花园
链接:https://leetcode-cn.com/problems/minimum-garden-perimeter-to-collect-enough-apples/
思路:

​ 使用二分的方法枚举边长即可,具体细节看代码注释

代码实现:
typedef long long ll ;
class Solution {
public:
    bool check(ll x , ll n){    //如果边长为x,苹果的总数>= n,返回ture,否则返回false
        ll y = (x + 1) * x / 2 ;
        ll tot = (2 * y + x * x) * (x + 1) * 2 ;
        if(tot >= n)
            return true ;
        return false ;
    }

    long long minimumPerimeter(long long n) {
        ll l = 0 , r = 1e6 + 10 ;
        while(l < r){
            ll mid = (l + r) / 2 ;
            if(check(mid , n))
                r = mid ;
            else
                l = mid + 1 ;
        }
        return l * 8 ;
    }
};

/*
设x为正方形的边到(0,0)的距离
x:

(0,0) 1 2 3 4 5 ... x
1     2 3 4 5 6 ....x+1
2     3 4 5 6 7 ... x+2
3                   x+3
4                   x+4
5  
.  
.  
.  
x     x+1 x+2 ....  x+x

第1列苹果总和: (x + 1) * x / 2
第2列苹果总和: (x + 1) * x / 2 + x
第3列苹果总和: (x + 1) * x / 2 + 2 * x
...
第x列苹果总和: (x + 1) * x / 2 + x * x

设:y = (x + 1) * x / 2 

那么y的负半轴上的苹果加上右下角的苹果的总和:tot = (y + y + x * x) * (x + 1) / 2 ;
那么整个土地的苹果总和为:ans = tot * 4

*/
第四题、统计特殊子序列的数目
链接:https://leetcode-cn.com/problems/count-number-of-special-subsequences/
思路:

​ 使用动态规划,推导出状态转移方程,具体看代码注释

代码实现:
const int N = 1e5 + 10 ;
const int mod = 1e9 + 7 ;
class Solution {
    int f[N][3] ;
    /*
    f[i][0] 表示0...0的子序列数
    f[i][1] 表示0..01..1的子序列数
    f[i][2] 表示0..01..12..2的子序列数
    */
public:
    int countSpecialSubsequences(vector<int>& nums) {
        int n = nums.size() ;
        for(int i = 1 ; i <= n ; ++ i){
            f[i][0] = f[i - 1][0] ;     //继承i - 1的
            f[i][1] = f[i - 1][1] ;
            f[i][2] = f[i - 1][2] ;
            if(nums[i - 1] == 0)
                f[i][0] = (f[i - 1][0] * 2 + 1) % mod ;
                /*
                如果当前数字为0,那么f[i][0]有三种来源:
                    第一、由f[i - 1][0]的情况不变得来,情况数为f[i - 1][0]
                    第二、由f[i - 1][0]的情况后面加上一个0得来,情况数为f[i - 1][0]
                    第三、仅由当前这个0组成的子序列,情况数为1
                */
            else if(nums[i - 1] == 1)
                f[i][1] = ((f[i - 1][1] * 2) % mod + f[i - 1][0]) % mod ;
                /*
                如果当前数字为1,那么f[i][1]的来源有三种:
                    第一、由f[i - 1][1]的情况不变得来,情况数为f[i - 1][1]
                    第二、由f[i - 1][1]的情况后面加上当前这个1得来,情况数为f[i - 1][1]
                    第三、由f[i - 1][0]的情况后面加上当前这个1得来,情况数为f[i - 1][0]
                */
            else
                f[i][2] = ((f[i - 1][2] * 2) % mod + f[i - 1][1]) % mod ;
                /*
                如果当前数字为2,那么f[i][1]的来源有三种:
                    第一、由f[i - 1][2]的情况不变得来,情况数为f[i - 1][2]
                    第二、由f[i - 1][2]的情况后面加上当前这个2得来,情况数为f[i - 1][2]
                    第三、由f[i - 1][1]的情况后面加上当前这个2得来,情况数为f[i - 1][1]
                */
        }
        return f[n][2] ;    //返回结果
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述: 给出两个非空链表来表示两个非负整数。其中,它们各自的位数是按照逆序的方式存储的,并且它们的每个节点只能存储一位数字。 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 您可以假设除了数字 0 之外,这两个数都不会以零开头。 示例: 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807 解题思路: 题目中要求我们按照逆序的方式存储两个非负整数,也就是说链表的头节点表示该数的个位,第二个节点表示该数的十位,以此类推。 因此,我们可以从两个链表的头节点开始,对应位相加,并记录进位,将结果添加到新的链表中。如果有进位,需要在下一位相加时加上进位。 需要注意的是,当两个链表的长度不一致时,可以将较短的链表的缺失位看作是 0。 最后,如果最高位有进位,还需要在新链表的最高位添加一个值为 1 的节点。 C 语言代码实现: /** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){ struct ListNode *head = NULL, *tail = NULL; int carry = 0; while (l1 || l2) { int n1 = l1 ? l1->val : 0; int n2 = l2 ? l2->val : 0; int sum = n1 + n2 + carry; if (!head) { head = tail = malloc(sizeof(struct ListNode)); tail->val = sum % 10; tail->next = NULL; } else { tail->next = malloc(sizeof(struct ListNode)); tail = tail->next; tail->val = sum % 10; tail->next = NULL; } carry = sum / 10; if (l1) l1 = l1->next; if (l2) l2 = l2->next; } if (carry > 0) { tail->next = malloc(sizeof(struct ListNode)); tail = tail->next; tail->val = carry; tail->next = NULL; } return head; }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值