文章目录
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]=j∑i−1(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 的 得分之和 。
思路:
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;
}
};