LeetCode第75场双周赛

本文介绍了三位程序员在解决计算机科学问题时的思路和AC代码。他们分别处理了数字位翻转次数的计算、数组三角和的求解以及在特定约束下的建筑选择方案数。通过位操作和数组处理,展示了如何高效地解决这些算法问题。
摘要由CSDN通过智能技术生成

6033. 转换数字的最少位翻转次数

题目链接

题目描述

一次 位翻转 定义为将数字 x 二进制中的一个位进行 翻转 操作,即将 0 变成 1 ,或者将 1 变成 0 。

比方说,x = 7 ,二进制表示为 111 ,我们可以选择任意一个位(包含没有显示的前导 0 )并进行翻转。比方说我们可以翻转最右边一位得到 110 ,或者翻转右边起第二位得到 101 ,或者翻转右边起第五位(这一位是前导 0 )得到 10111 等等。
给你两个整数 start 和 goal ,请你返回将 start 转变成 goal 的 最少位翻转 次数。

思路

简单来说,就是要知道两个数用二进制表示时,对应位不一样的位数,那最简单的想法不就是直接暴力遍历两个数二进制表示的每一位,看看一样不一样,不一样就要翻转,计数加一.

第二种思路就是利用一个异或的思想(^),因为1 ^ 0 = 1;不一样的情况下异或得 1 ,代表翻转了一次.那么我们就可以先把两个数异或,然后看看异或结果有几个位是 1 ,就是反转了几次

AC代码

int Change(int start,int goal){
    int count = 0;
    for(int i=0;i<32;i++){
            if(((start>>i)&1) != ((goal>>i)&1)){
                count++;
            }
        }
    return count;
}
int minBitFlips(int start, int goal){
    return Change(start,goal);
}
int Count(int num){
    int count = 0;
    for(int i=0;i<32;i++){
        count += (num >> i) & 1;
    }
    return count;
}
int minBitFlips(int start, int goal){
    return Count(start^goal);
}

6034. 数组的三角和

题目链接

题目描述

给你一个下标从 0 开始的整数数组 nums ,其中 nums[i] 是 0 到 9 之间(两者都包含)的一个数字。

nums 的 三角和 是执行以下操作以后最后剩下元素的值:

nums 初始包含 n 个元素。如果 n == 1 ,终止 操作。否则,创建 一个新的下标从 0 开始的长度为 n - 1 的整数数组 newNums 。
对于满足 0 <= i < n - 1 的下标 i ,newNums[i] 赋值 为 (nums[i] + nums[i+1]) % 10 ,% 表示取余运算。
将 newNums 替换 数组 nums 。
从步骤 1 开始 重复 整个过程。
请你返回 nums 的三角和。
在这里插入图片描述

思路

直接模拟这个过程即可,每次都把数组内相邻两数相加的和%10,然后存到一个新数组中,最后再把处理完的这个新数组作为下一次操作的数组返回

AC代码

int triangularSum(int* nums, int numsSize){
    while(numsSize > 1){
        for(int i=0;i<numsSize-1;i++){
        nums[i] = (nums[i] + nums[i+1]) % 10;
        }
        numsSize--;
    }
    return nums[0];

}
class Solution {
    public int triangularSum(int[] nums) {
        int len = nums.length;
        while(len > 1){
            for(int i=0;i<nums.length-1;i++){
                nums[i] = (nums[i] + nums[i+1]) % 10;
            }
            len--;
        }
        return nums[0];
    }
}

6035. 选择建筑的方案数

前缀和问题

题目链接

题目描述

给你一个下标从 0 开始的二进制字符串 s ,它表示一条街沿途的建筑类型,其中:

s[i] = ‘0’ 表示第 i 栋建筑是一栋办公楼,
s[i] = ‘1’ 表示第 i 栋建筑是一间餐厅。
作为市政厅的官员,你需要随机 选择 3 栋建筑。然而,为了确保多样性,选出来的 3 栋建筑 相邻 的两栋不能是同一类型。

比方说,给你 s = “001101” ,我们不能选择第 1 ,3 和 5 栋建筑,因为得到的子序列是 “011” ,有相邻两栋建筑是同一类型,所以 不合 题意。
请你返回可以选择 3 栋建筑的 有效方案数 。

在这里插入图片描述

思路

在这里插入图片描述
来尝试理解一下上面的想法:我们要求的是长度为三的字符串,要求字符串的相邻两位不能是一样的,也就是只能是 101 和 010两种,问题所求是从题给的字符串中能取出多少种不同位置的方案.
将这个问题拆分来看,我们可以先考虑取第一个字符有几种可能,然后在第一个字符的基础上取第二个字符有多少种可能,最后计算在第二个字符的基础上取第三个字符的可能.
也就是说,当你只取一个字符长度为1时,不管你取到的是0 还是 1,他都算作是一个方案(emmm…想达到长度为3,那你就必须要从长度为1 开始取----我是这么想的)
所以 f [ 1 ] [ i ] = 1 f[1][i] = 1 f[1][i]=1.
然后,在第一个字符的基础上取出第二个字符,这时就得判断去除掉第二个字符与第一个字符是否一样,不一样就是一个可行的方案,把这些求和 就是取出长度为 2 2 2 的字符串的不同方案数: f [ 2 ] [ i ] = ∑ j i − 1 ( s [ j ] ? 0 : 1 ) f[2][i] = \sum_{j}^{i-1}(s[j] ? 0 : 1) f[2][i]=ji1(s[j]?0:1)
然后继续重复上面的操作,取出第三个字符与第二个字符进行比较,最后将不一样的情况累加起来得到最后的方案数.

理解一下上面的操作就会发现,我们其实做了三个相似的操作,都是在取出新字符以后与它前面的字符比较,判断是否一样,不一样的话就可以基于取出上个字符的方案数进行累加.
将三个操作放进一个for循环中for(int i=0;i<=3;i++),当长度为1时,方案数都是1: f [ 1 ] [ i ] = 1 f[1][i] = 1 f[1][i]=1;

AC代码

#define ll long long
#define maxn 100005

ll sum[2][maxn];
ll f[4][maxn];

long long numberOfWays(char * s){
    ll ret = 0;
    int n = strlen(s);
    int x, i, j;

    for(j = 1; j <= 3; ++j) {
        if(j == 1) {
            for(i = 0; i < n; ++i) {
                f[j][i] = 1;
            }
            continue;
        }
        for(x = 0; x < 2; ++x) {
            for(i = 0; i < n; ++i) {
                sum[x][i] = (s[i] - '0') == x ? f[j-1][i] : 0;
                if(i) {
                    sum[x][i] += sum[x][i-1];
                }
            }
        }
        for(i = 0; i < j-1; ++i) {
            f[j][i] = 0;
        }
        for(i = j-1; i < n; ++i) {
            x = s[i] - '0';
            f[j][i] = sum[x^1][i-1];
            if(j == 3)
                ret += f[j][i];
        }
    }

    return ret;

}

6036. 构造字符串的总得分和

二分+字符串哈希

题目链接

题目描述

你需要从空字符串开始 构造 一个长度为 n 的字符串 s ,构造的过程为每次给当前字符串 前面 添加 一个 字符。构造过程中得到的所有字符串编号为 1 到 n ,其中长度为 i 的字符串编号为 si 。

比方说,s = “abaca” ,s1 = “a” ,s2 = “ca” ,s3 = “aca” 依次类推。
si 的 得分 为 si 和 sn 的 最长公共前缀 的长度(注意 s = sn )。

给你最终的字符串 s ,请你返回每一个 si 的 得分之和 。

思路:

参照LeetCode 6036. 构造字符串的总得分和

AC代码

#define ull unsigned long long
#define maxn 100010
#define P 10207
ull h[maxn], p[maxn];

void initHash(const char *s) {
    // 这个字符串是从 1 - n-1
    int n = strlen(s);
    int i;
    p[0] = 1;
    h[0] = 0;
    for(i = 1; i < n; ++i) {
        h[i] = h[i-1] * P + s[i];
        p[i] = p[i-1] * P;
    }
}

ull getSubHash(int l, int r) {
    return h[r] - h[l-1] * p[r - l + 1];
}


class Solution {
public:
    long long sumScores(string s) {
        s = "#" + s;
        long long ret = 0;
        int n = s.size() - 1;
        initHash(s.c_str());
        for(int i = 1; i <= n; ++i) {
            int l1 = n - i + 1;
            int l2 = 1;
            int l = 1, r = i;
            int ans = 0;
            while(l <= r) {
                int mid = (l + r) >> 1;
                if(getSubHash(l1, l1 + mid - 1) == getSubHash(l2, l2 + mid - 1)) {
                    ans = mid;
                    l = mid + 1;
                }else {
                    r = mid - 1;
                }
            }
            ret += ans;
        }
        return ret;
    }
};

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值