image.png
虽然是手速场,但没有Wrong就很开心。

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

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

  • 比方说,x = 7 ,二进制表示为 111 ,我们可以选择任意一个位(包含没有显示的前导 0 )并进行翻转。比方说我们可以翻转最右边一位得到 110 ,或者翻转右边起第二位得到 101 ,或者翻转右边起第五位(这一位是前导 0 )得到 10111 等等。

给你两个整数 start 和 goal ,请你返回将 start 转变成 goal 的 最少位翻转 次数。

示例 1:
输入:start = 10, goal = 7 输出:3 解释:10 和 7 的二进制表示分别为 1010 和 0111 。我们可以通过 3 步将 10 转变成 7 : - 翻转右边起第一位得到:1010 -> 1011 。 - 翻转右边起第三位:1011 -> 1111 。 - 翻转右边起第四位:1111 -> 0111 。 我们无法在 3 步内将 10 转变成 7 。所以我们返回 3 。
示例 2:
输入:start = 3, goal = 4 输出:3 解释:3 和 4 的二进制表示分别为 011 和 100 。我们可以通过 3 步将 3 转变成 4 : - 翻转右边起第一位:011 -> 010 。 - 翻转右边起第二位:010 -> 000 。 - 翻转右边起第三位:000 -> 100 。 我们无法在 3 步内将 3 变成 4 。所以我们返回 3 。

提示:

  • 0 <= start, goal <= 109

思路:
模拟

  1. class Solution {
  2. public int minBitFlips(int s, int p) {
  3. int cnt = 0;
  4. for (int i = 0; i < 31; i++) {
  5. int x = s >> i & 1, y = p >> i & 1;
  6. if (x != y)
  7. cnt++;
  8. }
  9. return cnt;
  10. }
  11. }

2221. 数组的三角和

显示英文描述
我的提交返回竞赛

  • 通过的用户数3074
  • 尝试过的用户数3152
  • 用户总通过次数3112
  • 用户总提交次数3945
  • 题目难度Medium

给你一个下标从 0 开始的整数数组 nums ,其中 nums[i] 是 0 到 9 之间(两者都包含)的一个数字。
nums 的 三角和 是执行以下操作以后最后剩下元素的值:

  1. nums 初始包含 n 个元素。如果 n == 1 ,终止 操作。否则,创建 一个新的下标从 0 开始的长度为 n - 1 的整数数组 newNums 。
  2. 对于满足 0 <= i < n - 1 的下标 i ,newNums[i] 赋值 为 (nums[i] + nums[i+1]) % 10 ,% 表示取余运算。
  3. 将 newNums 替换 数组 nums 。
  4. 从步骤 1 开始 重复 整个过程。

请你返回 nums 的三角和。

示例 1:
image.png
输入:nums = [1,2,3,4,5] 输出:8 解释: 上图展示了得到数组三角和的过程。
示例 2:
输入:nums = [5] 输出:5 解释: 由于 nums 中只有一个元素,数组的三角和为这个元素自己。

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 9

思路:
模拟递推过程

  1. class Solution {
  2. public int triangularSum(int[] nums) {
  3. // int res = 0;
  4. int n = nums.length;
  5. if (n == 1) return nums[0];
  6. for (int i = n - 2; i >= 0; i--) {
  7. for (int j = 0; j <= i; j++) {
  8. nums[j] = (nums[j] + nums[j + 1]) % 10;
  9. }
  10. }
  11. return nums[0];
  12. }
  13. }

6035. 选择建筑的方案数

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

  • s[i] = ‘0’ 表示第 i 栋建筑是一栋办公楼,
  • s[i] = ‘1’ 表示第 i 栋建筑是一间餐厅。

作为市政厅的官员,你需要随机 选择 3 栋建筑。然而,为了确保多样性,选出来的 3 栋建筑 相邻 的两栋不能是同一类型。

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

请你返回可以选择 3 栋建筑的 有效方案数

示例 1:
输入:s = “001101” 输出:6 解释: 以下下标集合是合法的: - [0,2,4] ,从 “0_01101” 得到 “010” - [0,3,4] ,从 “001101” 得到 “010” - [1,2,4] ,从 “001101” 得到 “010” - [1,3,4] ,从 “001101” 得到 “010” - [2,4,5] ,从 “001101“ 得到 “101” - [3,4,5] ,从 “001101_” 得到 “101” 没有别的合法选择,所以总共有 6 种方法。
示例 2:
输入:s = “11100” 输出:0 解释:没有任何符合题意的选择。

提示:

  • 3 <= s.length <= 105
  • s[i] 要么是 ‘0’ ,要么是 ‘1’ 。

思路:
只能选101或者010
枚举即可

  1. class Solution {
  2. public long numberOfWays(String s) {
  3. int n = s.length();
  4. int[] l0 = new int[n], r0 = new int[n];
  5. int[] l1 = new int[n], r1 = new int[n];
  6. int c0 = 0, c1 = 0;
  7. for (int i = 0; i < n; i++) {
  8. l0[i] = c0;
  9. l1[i] = c1;
  10. if (s.charAt(i) == '1')
  11. c1++;
  12. else
  13. c0++;
  14. }
  15. c0 = 0;
  16. c1 = 0;
  17. for (int i = n - 1; i >= 0; i--) {
  18. r0[i] = c0;
  19. r1[i] = c1;
  20. if (s.charAt(i) == '1')
  21. c1++;
  22. else
  23. c0++;
  24. }
  25. long res = 0;
  26. for (int i = 0; i < n; i++) {
  27. if (s.charAt(i) == '0') {
  28. res += 1L * l1[i] * r1[i];
  29. } else {
  30. res += 1L * l0[i] * r0[i];
  31. }
  32. }
  33. return res;
  34. }
  35. }

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

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

  • 比方说,s = “abaca” ,s1 == “a” ,s2 == “ca” ,s3 == “aca” 依次类推。

si 的 得分 为 si 和 sn 的 最长公共前缀 的长度(注意 s == sn )。
给你最终的字符串 s ,请你返回每一个_ _si 的 得分之和

示例 1:
输入:s = “babab” 输出:9 解释: s1 == “b” ,最长公共前缀是 “b” ,得分为 1 。 s2 == “ab” ,没有公共前缀,得分为 0 。 s3 == “bab” ,最长公共前缀为 “bab” ,得分为 3 。 s4 == “abab” ,没有公共前缀,得分为 0 。 s5 == “babab” ,最长公共前缀为 “babab” ,得分为 5 。 得分和为 1 + 0 + 3 + 0 + 5 = 9 ,所以我们返回 9 。
示例 2 :
输入:s = “azbazbzaz” 输出:14 解释: s2 == “az” ,最长公共前缀为 “az” ,得分为 2 。 s6 == “azbzaz” ,最长公共前缀为 “azb” ,得分为 3 。 s9 == “azbazbzaz” ,最长公共前缀为 “azbazbzaz” ,得分为 9 。 其他 si 得分均为 0 。 得分和为 2 + 3 + 9 = 14 ,所以我们返回 14 。

提示:

  • 1 <= s.length <= 105
  • s 只包含小写英文字母。

思路:
方法1:哈希 + 二分
方法2:扩展KMP(Z函数)板子题

  1. class Solution {
  2. int N = 100010, P = 13331;
  3. long[] h = new long[N], p = new long[N];
  4. public long sumScores(String s) {
  5. int n = s.length();
  6. p[0] = 1;
  7. for (int i = 1; i <= n; i++) {
  8. p[i] = p[i-1] * P;
  9. h[i] = h[i-1] * P + s.charAt(i - 1);
  10. }
  11. long res = n;
  12. for (int i = 2; i <= n; i++) {
  13. if (s.charAt(i - 1) != s.charAt(0))
  14. continue;
  15. int l = i, r = n;
  16. while (l < r) {
  17. int mid = l + r + 1 >> 1;
  18. if (get(i, mid) != get(1, mid - i + 1))
  19. r = mid - 1;
  20. else
  21. l = mid;
  22. }
  23. res += l - i + 1;
  24. }
  25. return res;
  26. }
  27. long get(int l, int r) {
  28. return h[r] - h[l - 1] * p[r - l + 1];
  29. }
  30. }
  1. class Solution {
  2. public long sumScores(String s) {
  3. int[] z = z_func(s);
  4. long res = s.length();
  5. for (int x : z)
  6. res += x;
  7. return res;
  8. }
  9. int[] z_func(String s) {
  10. int n = s.length(), l = 0, r = 0;
  11. int[] z = new int[n];
  12. for (int i = 1; i < n; i++) {
  13. if (i <= r && z[i - l] < r - i + 1)
  14. z[i] = z[i - l];
  15. else {
  16. z[i] = Math.max(0, r - i + 1);
  17. while (i + z[i] < n && s.charAt(i + z[i]) == s.charAt(z[i]))
  18. z[i]++;
  19. }
  20. if (i + z[i] - 1 > r) {
  21. l = i;
  22. r = i + z[i] - 1;
  23. }
  24. }
  25. return z;
  26. }
  27. }