【Leetcode Sheet】Weekly Practice 23

文章介绍了如何通过模拟和算法技巧解决LeetCode中的五个问题,包括摩天轮运营策略、字符串重复字符去除、链表节点移除、列覆盖行数最大化的二进制枚举和链表中插入最大公约数。每个问题涉及不同IT技术,如模拟、动态规划和数据结构应用。
摘要由CSDN通过智能技术生成

Leetcode Test

1599 经营摩天轮的最大利润(1.1)

你正在经营一座摩天轮,该摩天轮共有 4 个座舱 ,每个座舱 最多可以容纳 4 位游客 。你可以 逆时针 轮转座舱,但每次轮转都需要支付一定的运行成本 runningCost 。摩天轮每次轮转都恰好转动 1 / 4 周。

给你一个长度为 n 的数组 customerscustomers[i] 是在第 i 次轮转(下标从 0 开始)之前到达的新游客的数量。这也意味着你必须在新游客到来前轮转 i 次。每位游客在登上离地面最近的座舱前都会支付登舱成本 boardingCost ,一旦该座舱再次抵达地面,他们就会离开座舱结束游玩。

你可以随时停下摩天轮,即便是 在服务所有游客之前 。如果你决定停止运营摩天轮,为了保证所有游客安全着陆,将免费进行所有后续轮转 。注意,如果有超过 4 位游客在等摩天轮,那么只有 4 位游客可以登上摩天轮,其余的需要等待 下一次轮转

返回最大化利润所需执行的 最小轮转次数 。 如果不存在利润为正的方案,则返回 -1

提示:

  • n == customers.length
  • 1 <= n <= 105
  • 0 <= customers[i] <= 50
  • 1 <= boardingCost, runningCost <= 100

【模拟】

int minOperationsMaxProfit(int* customers, int customersSize, int boardingCost, int runningCost){
    int current=0;//当前还有多少游客没有登上摩天轮
    int count=0;//当前轮转的次数
    int maxCount=0;//最大利润,轮转的次数
    int maxProfit=0;  //最大利润
    int tmpProfit=0;//当前轮转的所获利润
    for(int i=0;i<customersSize;i++){
        //统计当前游客数
        current=current+customers[i];
        //每个座舱最多可以容纳4位游客
        if(current>=4){
            tmpProfit=tmpProfit+(boardingCost*4-1*runningCost);
            current=current-4;
        }else{
            //游客数少于4,让他们全部上去
            tmpProfit=tmpProfit+(boardingCost*current-1*runningCost);
            current=0;
        }
        //记录目前的轮转
        count++;
        //更新最大利润和最大利润对应的轮转
        if(maxProfit<tmpProfit){
            maxProfit=tmpProfit;
            maxCount=count;
        }

    }
    //没有新游客到达,但是还有游客没有乘坐摩天轮,结束是直到所有游客都乘坐了摩天轮
    //循环的内容和之前一样
    while(current!=0){
        //每个座舱最多可以容纳4位游客
        if(current>=4){
            tmpProfit=tmpProfit+(boardingCost*4-1*runningCost);
            current=current-4;
        }else{
            //游客数少于4,让他们全部上去
            tmpProfit=tmpProfit+(boardingCost*current-1*runningCost);
            current=0;
        }
        //记录目前的轮转
        count++;
        //更新最大利润和最大利润对应的轮转
        if(maxProfit<tmpProfit){
            maxProfit=tmpProfit;
            maxCount=count;
        }

    }
    //如果不存在利润为正的方案就返回-1,因为maxCount是从0开始的,而且每次都更新最大
    //所有当利润为0时就是不存在利润为正的方案
    return maxCount!=0?maxCount:-1;
}

466 统计重复个数(1.2)

定义 str = [s, n] 表示 strn 个字符串 s 连接构成。

  • 例如,str == ["abc", 3] =="abcabcabc"

如果可以从 s2 中删除某些字符使其变为 s1,则称字符串 s1 可以从字符串 s2 获得。

  • 例如,根据定义,s1 = "abc" 可以从 s2 = "ab**\*dbe***c" 获得,仅需要删除加粗且用斜体标识的字符。

现在给你两个字符串 s1s2 和两个整数 n1n2 。由此构造得到两个字符串,其中 str1 = [s1, n1]str2 = [s2, n2]

请你找出一个最大整数 m ,以满足 str = [str2, m] 可以从 str1 获得。

提示:

  • 1 <= s1.length, s2.length <= 100
  • s1s2 由小写英文字母组成
  • 1 <= n1, n2 <= 106

【循环节】466. 统计重复个数 - 力扣(LeetCode)

int getMaxRepetitions(char * s1, int n1, char * s2, int n2){
    if(n1==0) return 0;
    int len1=strlen(s1),len2=strlen(s2);
    int *s2_id=malloc(sizeof(int)*(len2+1)),*s2_cnt=malloc(sizeof(int)*(len2+1));
    int id=0,cnt=0;

    //查找循环节
    for(int i=0;i<n1;i++){
        for(int j=0;j<len1;j++){
            if(s1[j]==s2[id]){
                cnt = id==len2-1 ? cnt+1 : cnt;
                id = id==len2-1 ? 0 : id+1;
            }
        }
        //record
        s2_id[i]=id;
        s2_cnt[i]=cnt;

        //search
        for(int j=0;j<i;j++){
            if(s2_id[j]==s2_id[i]){
                //循环节中的s2的个数乘以循环次数
                int core=(s2_cnt[i]-s2_cnt[j])*((n1-j-1)/(i-j));
                //将剩余的s1的循环个数加到前面,计算除循环节外的个数
                int addition=s2_cnt[j+((n1-1-j)%(i-j))];

                return (addition+core)/n2;
            }
        }
    }

    return s2_cnt[n1-1]/n2;
}

2487 从链表中移除节点(1.3)

给你一个链表的头节点 head

移除每个右侧有一个更大数值的节点。

返回修改后链表的头节点 head

提示:

  • 给定列表中的节点数目在范围 [1, 105]
  • 1 <= Node.val <= 105

【递归】

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeNodes(struct ListNode* head) {
    if (head==NULL) return NULL;
    head->next=removeNodes(head->next);
    if(head->next != NULL && head->val < head->next->val){
        return head->next;
    }
    else{
        return head;
    }
}

2397 被列覆盖的最多行数(1.4)

给你一个下标从 0 开始、大小为 m x n 的二进制矩阵 matrix ;另给你一个整数 numSelect,表示你必须从 matrix 中选择的 不同 列的数量。

如果一行中所有的 1 都被你选中的列所覆盖,则认为这一行被 覆盖 了。

形式上,假设 s = {c1, c2, ...., cnumSelect} 是你选择的列的集合。对于矩阵中的某一行 row ,如果满足下述条件,则认为这一行被集合 s 覆盖

  • 对于满足 matrix[row][col] == 1 的每个单元格 matrix[row][col]0 <= col <= n - 1),col 均存在于 s 中,或者
  • row不存在 值为 1 的单元格。

你需要从矩阵中选出 numSelect 个列,使集合覆盖的行数最大化。

返回一个整数,表示可以由 numSelect 列构成的集合 覆盖最大行数

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 12
  • matrix[i][j] 要么是 0 要么是 1
  • 1 <= numSelect <= n

【二进制枚举】

int maximumRows(int **matrix, int matrixSize, int *matrixColSize, int numSelect) {
    int m = matrixSize, n = matrixColSize[0];
    int *mask = (int *)malloc(sizeof(int) * m);
    for (int i = 0; i < m; i++) {
        mask[i] = 0;
        for (int j = 0; j < n; j++) {
            mask[i] += matrix[i][j] << (n - 1 - j);
        }
    }
    int res = 0, limit = 1 << n;
    for (int cur = 1; cur < limit; cur++) {
        if (__builtin_popcount(cur) != numSelect) {
            continue;
        }
        int t = 0;
        for (int j = 0; j < m; j++) {
            if ((mask[j] & cur) == mask[j]) {
                t++;
            }
        }
        res = res > t ? res : t;
    }
    free(mask);
    return res;
}

1944 队列中可以看到的人数(1.5)

n 个人排成一个队列,从左到右 编号为 0n - 1 。给你以一个整数数组 heights ,每个整数 互不相同heights[i] 表示第 i 个人的高度。

一个人能 看到 他右边另一个人的条件是这两人之间的所有人都比他们两人 。更正式的,第 i 个人能看到第 j 个人的条件是 i < jmin(heights[i], heights[j]) > max(heights[i+1], heights[i+2], ..., heights[j-1])

请你返回一个长度为 n 的数组 answer ,其中 answer[i] 是第 i 个人在他右侧队列中能 看到人数

提示:

  • n == heights.length
  • 1 <= n <= 105
  • 1 <= heights[i] <= 105
  • heights 中所有数 互不相同

【单调栈】

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* canSeePersonsCount(int* heights, int heightsSize, int* returnSize) {
    int n = heightsSize;
    int stackSize = 0;
    int* stack = (int*)malloc(n * sizeof(int));
    int* res = (int*)malloc(n * sizeof(int));
    *returnSize = n;

    for (int i = n - 1; i >= 0; i--) {
        int h = heights[i];
        res[i] = 0;
        while (stackSize > 0 && stack[stackSize - 1] <= h) {
            stackSize--;
            res[i] += 1;
        }
        if (stackSize > 0) {
            res[i] += 1;
        }
        stack[stackSize++] = h;
    }
    free(stack);
    return res;
}

2807 在链表中插入最大公约数(1.6)

给你一个链表的头 head ,每个结点包含一个整数值。

在相邻结点之间,请你插入一个新的结点,结点值为这两个相邻结点值的 最大公约数

请你返回插入之后的链表。

两个数的 最大公约数 是可以被两个数字整除的最大正整数。

提示:

  • 链表中结点数目在 [1, 5000] 之间。
  • 1 <= Node.val <= 1000

【模拟】

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
int gcd(int a, int b) {
    while (b != 0) {
        int tmp = a % b;
        a = b;
        b = tmp;
    }
    return a;
}

struct ListNode* insertGreatestCommonDivisors(struct ListNode* head) {
    struct ListNode * node = head;
    while (node->next) {
        struct ListNode *newNode = (struct ListNode *)malloc(sizeof(struct ListNode));
        newNode->val = gcd(node->val, node->next->val);
        newNode->next = node->next;
        node->next = newNode;
        node = newNode->next;
    }
    return head;
}

383 赎金信(1.7)

给你两个字符串:ransomNotemagazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false

magazine 中的每个字符只能在 ransomNote 中使用一次。

提示:

  • 1 <= ransomNote.length, magazine.length <= 105
  • ransomNotemagazine 由小写英文字母组成

【hash-count】

bool canConstruct(char* ransomNote, char* magazine) {
    if(strlen(ransomNote)>strlen(magazine)){
        return false;
    }
    
    int cnt[26]={0};

    for(int i=0;i<strlen(magazine);i++){
        cnt[magazine[i]-'a']++;
    }

    for(int i=0;i<strlen(ransomNote);i++){
        char t=ransomNote[i];
        if(cnt[t-'a']<=0){
            return 0;
        }
        cnt[t-'a']--;
    }
    return 1;
}
  • 17
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

MorleyOlsen

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

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

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

打赏作者

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

抵扣说明:

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

余额充值