【Leetcode Sheet】Weekly Practice 25

Leetcode Test

82 删除排序链表中的重复元素Ⅱ(1.15)

给定一个已排序的链表的头 head删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表

提示:

  • 链表中节点数目在范围 [0, 300]
  • -100 <= Node.val <= 100
  • 题目数据保证链表已经按升序 排列

【模拟】

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* deleteDuplicates(struct ListNode* head) {
    if(head==NULL){
        return NULL;
    }

    struct ListNode* dummy=malloc(sizeof(struct ListNode));
    dummy->next=head;

    struct ListNode* cur=dummy;
    while(cur->next && cur->next->next){
        if(cur->next->val == cur->next->next->val){
            int x=cur->next->val;
            while(cur->next && cur->next->val == x){
                cur->next=cur->next->next;
            }
        }
        else{
            cur=cur->next;
        }
    }
    return dummy->next;
}

2719 统计整数数目(1.16)

给你两个数字字符串 num1num2 ,以及两个整数 max_summin_sum 。如果一个整数 x 满足以下条件,我们称它是一个好整数:

  • num1 <= x <= num2
  • min_sum <= digit_sum(x) <= max_sum.

请你返回好整数的数目。答案可能很大,请返回答案对 109 + 7 取余后的结果。

注意,digit_sum(x) 表示 x 各位数字之和。

提示:

  • 1 <= num1 <= num2 <= 1022
  • 1 <= min_sum <= max_sum <= 400

【一次记忆化搜索】2719. 统计整数数目 - 力扣(LeetCode)

class Solution {
public:
    int count(string num1, string num2, int min_sum, int max_sum) {
        int n = num2.length();
        num1 = string(n - num1.length(), '0') + num1; // 补前导零,和 num2 对齐

        vector<vector<int>> memo(n, vector<int>(min(9 * n, max_sum) + 1, -1));
        function<int(int, int, bool, bool)> dfs = [&](int i, int sum, bool limit_low, bool limit_high) -> int {
            if (sum > max_sum) { // 非法
                return 0;
            }
            if (i == n) {
                return sum >= min_sum;
            }
            if (!limit_low && !limit_high && memo[i][sum] != -1) {
                return memo[i][sum];
            }

            int lo = limit_low ? num1[i] - '0' : 0;
            int hi = limit_high ? num2[i] - '0' : 9;

            int res = 0;
            for (int d = lo; d <= hi; d++) { // 枚举当前数位填 d
                res = (res + dfs(i + 1, sum + d, limit_low && d == lo, limit_high && d == hi)) % 1'000'000'007;
            }

            if (!limit_low && !limit_high) {
                memo[i][sum] = res;
            }
            return res;
        };

        return dfs(0, 0, true, true);
    }
};

2744 最大字符串配对数目(1.17)

给你一个下标从 0 开始的数组 words ,数组中包含 互不相同 的字符串。

如果字符串 words[i] 与字符串 words[j] 满足以下条件,我们称它们可以匹配:

  • 字符串 words[i] 等于 words[j] 的反转字符串。
  • 0 <= i < j < words.length

请你返回数组 words 中的 最大 匹配数目。

注意,每个字符串最多匹配一次。

提示:

  • 1 <= words.length <= 50
  • words[i].length == 2
  • words 包含的字符串互不相同。
  • words[i] 只包含小写英文字母。

【暴力】

int maximumNumberOfStringPairs(char ** words, int wordsSize){
    int ret=0;
    for(int i=0;i<wordsSize;i++){
        for(int j=i+1;j<wordsSize;j++){
            if(words[i][0]==words[j][1] && words[i][1]==words[j][0]){
                ret++;
            }
        }
    }
    return ret;
}

2171 拿出最少数目的魔法豆(1.18)

给定一个 正整数 数组 beans ,其中每个整数表示一个袋子里装的魔法豆的数目。

请你从每个袋子中 拿出 一些豆子(也可以 不拿出),使得剩下的 非空 袋子中(即 至少还有一颗 魔法豆的袋子)魔法豆的数目 相等。一旦把魔法豆从袋子中取出,你不能再将它放到任何袋子中。

请返回你需要拿出魔法豆的 最少数目

提示:

  • 1 <= beans.length <= 105
  • 1 <= beans[i] <= 105

【数学】2171. 拿出最少数目的魔法豆 - 力扣(LeetCode)

int cmp(void *a,void *b){
    return *(int*)a-*(int*)b;
}

long long minimumRemoval(int* beans, int beansSize){
    qsort(beans,beansSize,sizeof(int),cmp);
    long long sum=0,mx=0;
    int n=beansSize;
    for(int i=0;i<n;i++){
        sum+=beans[i];
        mx=fmax(mx,(long long)(n-i)*beans[i]);
    }
    return sum-mx;
}

2809 使数组和小于等于 x 的最少时间(1.19)

给你两个长度相等下标从 0 开始的整数数组 nums1nums2 。每一秒,对于所有下标 0 <= i < nums1.lengthnums1[i] 的值都增加 nums2[i] 。操作 完成后 ,你可以进行如下操作:

  • 选择任一满足 0 <= i < nums1.length 的下标 i ,并使 nums1[i] = 0

同时给你一个整数 x

请你返回使 nums1 中所有元素之和 小于等于 x 所需要的 最少 时间,如果无法实现,那么返回 -1

提示:

  • 1 <= nums1.length <= 103
  • 1 <= nums1[i] <= 103
  • 0 <= nums2[i] <= 103
  • nums1.length == nums2.length
  • 0 <= x <= 106

【动态规划】

static int cmp(const void *a, const void *b) {
    return ((int *)a)[0] - ((int *)b)[0];
}

int minimumTime(int* nums1, int nums1Size, int* nums2, int nums2Size, int x) {
    int n = nums1Size;
    int dp[n + 1][n + 1];
    int nums[n][2];
    memset(dp, 0, sizeof(dp));
    for (int i = 0; i < n; i++) {
        nums[i][0] = nums2[i];
        nums[i][1] = nums1[i];
    }
    qsort(nums, n, sizeof(nums[0]), cmp);

    for (int j = 1; j <= n; j++) {
        int b = nums[j - 1][0], a = nums[j - 1][1];
        for (int i = j; i > 0; i--) {
            dp[j][i] = fmax(dp[j - 1][i], dp[j - 1][i - 1] + i * b + a);
        }
    }

    int s1 = 0, s2 = 0;
    for (int i = 0; i < n; i++) {
        s1 += nums1[i];
        s2 += nums2[i];
    }
    for (int i = 0; i <= n; i++) {
        if (s2 * i + s1 - dp[n][i] <= x) {
            return i;
        }
    }
    return -1;
}

2788 按分隔符拆分字符串(1.20)

给你一个字符串数组 words 和一个字符 separator ,请你按 separator 拆分 words 中的每个字符串。

返回一个由拆分后的新字符串组成的字符串数组,不包括空字符串

注意

  • separator 用于决定拆分发生的位置,但它不包含在结果字符串中。
  • 拆分可能形成两个以上的字符串。
  • 结果字符串必须保持初始相同的先后顺序。

提示:

  • 1 <= words.length <= 100
  • 1 <= words[i].length <= 20
  • words[i] 中的字符要么是小写英文字母,要么就是字符串 ".,|$#@" 中的字符(不包括引号)
  • separator 是字符串 ".,|$#@" 中的某个字符(不包括引号)

【模拟】

class Solution {
public:
    vector<string> splitWordsBySeparator(vector<string>& words, char separator) {
        vector<string> ans;	//结果字符串
        for (auto &w : words) {
            int j = 0;
            //遍历当前字符串的每个字母
            for (int i = 0; i <= w.size(); i++) {
                //遇到分隔符或结束符, 分割字符串 
                if (i == w.size() || w[i] == separator) {
                    if (i - j > 0) {
                        ans.push_back(w.substr(j, i - j));
                    }
                    j = i + 1;
                }
            }
        }
        return ans;
    }
};

410 分割数组的最大值(1.21)

给定一个非负整数数组 nums 和一个整数 k ,你需要将这个数组分成 k 个非空的连续子数组。

设计一个算法使得这 k 个子数组各自和的最大值最小。

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 106
  • 1 <= k <= min(50, nums.length)

【二分 + 贪心】

bool check(int* nums, int numsSize, int m, int x) {
    long long sum = 0;
    int cnt = 1;
    //x is mid figure
    for (int i = 0; i < numsSize; i++) {
        //surpass the mid
        if (sum + nums[i] > x) {
            cnt++;
            sum = nums[i];  //clear the sum
        } 
        else {
            sum += nums[i];
        }
    }
    return cnt <= m;
}

int splitArray(int* nums, int numsSize, int m) {
    long long left = 0, right = 0;
    for (int i = 0; i < numsSize; i++) {
        right += nums[i];
        left = fmax(nums[i],left);
    }
    //binary search
    while (left < right) {
        long long mid = (left + right)/2;
        if (check(nums, numsSize, m, mid)) {
            right = mid;
        } 
        else {
            left = mid + 1;
        }
    }
    return left;
}
  • 13
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

MorleyOlsen

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

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

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

打赏作者

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

抵扣说明:

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

余额充值