LeetCode1442. 形成两个异或相等数组的三元组数目 / 剑指 Offer 46. 把数字翻译成字符串 / 剑指 Offer 47. 礼物的最大价值
Posted Zephyr丶J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode1442. 形成两个异或相等数组的三元组数目 / 剑指 Offer 46. 把数字翻译成字符串 / 剑指 Offer 47. 礼物的最大价值相关的知识,希望对你有一定的参考价值。
1442. 形成两个异或相等数组的三元组数目
2021.5.18每日一题
题目描述
给你一个整数数组 arr 。
现需要从数组中取三个下标 i、j 和 k ,其中 (0 <= i < j <= k < arr.length) 。
a 和 b 定义如下:
a = arr[i] ^ arr[i + 1] ^ ... ^ arr[j - 1]
b = arr[j] ^ arr[j + 1] ^ ... ^ arr[k]
注意:^ 表示 按位异或 操作。
请返回能够令 a == b 成立的三元组 (i, j , k) 的数目。
示例 1:
输入:arr = [2,3,1,6,7]
输出:4
解释:满足题意的三元组分别是 (0,1,2), (0,2,2), (2,3,4) 以及 (2,4,4)
示例 2:
输入:arr = [1,1,1,1,1]
输出:10
示例 3:
输入:arr = [2,3]
输出:0
示例 4:
输入:arr = [1,3,5,7,9]
输出:3
示例 5:
输入:arr = [7,11,12,9,5,2,7,17,22]
输出:8
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-triplets-that-can-form-two-arrays-of-equal-xor
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
第一眼看到的思路,预处理前缀异或数组,方便取任意区间的异或结果
然后三层循环,定位三个点进行计算,尽然也过了,超过17.45%,想想怎么优化
class Solution {
public int countTriplets(int[] arr) {
//应该是先预处理了
int l = arr.length;
int[] pre = new int[l + 1];
//前i位的异或结果,方便取任意区间异或结果
for(int i = 1; i <= l; i++){
pre[i] = pre[i - 1] ^ arr[i - 1];
}
//三个点,难道要三层循环吗
//要求方案数,想想动态规划
//先暴力写一下
int res = 0;
for(int j = 1; j < l; j++){
for(int i = 0; i < j; i++){
for(int k = j; k < l; k++){
//i到j - 1, j 到k是否相同
if((pre[i] ^ pre[j]) == (pre[j] ^ pre[k + 1]))
res++;
}
}
}
return res;
}
}
然后看了一眼提示,又是自我怀疑的几秒钟
两个数组异或相等,那么这两个数组异或结果肯定为0
而一组数异或为0,那么将这个数组按随便一个节点分割成两部分,那么这两部分的异或结果都是相同的
所以两层循环
class Solution {
public int countTriplets(int[] arr) {
//应该是先预处理了
int l = arr.length;
int[] pre = new int[l + 1];
//前i位的异或结果,方便取任意区间异或结果
for(int i = 1; i <= l; i++){
pre[i] = pre[i - 1] ^ arr[i - 1];
}
//两层循环,找异或结果为0的区间
int res = 0;
for(int i = 0; i < l - 1; i++){
for(int j = i + 1; j < l; j++){
if((pre[i] ^ pre[j + 1]) == 0)
res += j - i;
}
}
return res;
}
}
万万没有想到还能一层循环
首先pre[i] ^ pre[j + 1] == 0 也可以写成pre[i] = pre[j + 1]
若对于下标 j , 满足条件的 i 为i1, i2, i3… im, 那么可取的区间(三元组)数目为:
j - i1 + j - i2 + … + j - im = m * j - (i1 + i2 + … + im)
因此遍历到下标j时,需要知道 m 和所有满足条件的下标 i 之和
可以采用两个哈希表来存储这两个结果
class Solution {
public int countTriplets(int[] arr) {
//应该是先预处理了
int l = arr.length;
int[] pre = new int[l + 1];
//前i位的异或结果,方便取任意区间异或结果
for(int i = 1; i <= l; i++){
pre[i] = pre[i - 1] ^ arr[i - 1];
}
//首先pre[i] ^ pre[j + 1] == 0 也可以写成pre[i] = pre[j + 1]
//若对于下标 j , 满足条件的 i 为i1, i2, i3... im, 那么可取的区间(三元组)数目为:
//j - i1 + j - i2 + .... + j - im = m * j - (i1 + i2 + ... + im)
//单层循环,用哈希表找m和满足条件的i的和
Map<Integer, Integer> count = new HashMap<>();
Map<Integer, Integer> sum = new HashMap<>();
int res = 0;
for(int i = 0; i < l; i++){
//这里的下标必须是i+1
if(count.containsKey(pre[i + 1])){
res += count.get(pre[i + 1]) * i - sum.get(pre[i + 1]);
}
//如果有这个数,就加1
count.put(pre[i], count.getOrDefault(pre[i], 0) + 1);
sum.put(pre[i], sum.getOrDefault(pre[i], 0) + i);
}
return res;
}
}
剑指 Offer 46. 把数字翻译成字符串
题目描述
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
转换成字符串,动态规划
class Solution {
public int translateNum(int num) {
//因为只需要统计翻译种数,而不需要具体的翻译方案,因此动态规划可以
//dp[i] = dp[i - 1] + dp[i - 2](如果是两位的话)
String s = String.valueOf(num);
int l = s.length();
int[] dp = new int[l + 1];
dp[0] = 1;
dp[1] = 1;
for(int i = 1; i < l; i++){
int k = 26;
if(i > 0){
char cur = s.charAt(i);
char pre = s.charAt(i - 1);
if(pre != '0'){
String ss = pre + "" + cur;
k = Integer.valueOf(ss);
}
}
dp[i + 1] = dp[i];
if(k <= 25)
dp[i + 1] += dp[i - 1];
}
return dp[l];
}
}
想想不转换成字符串,从低位到高位进行处理可以吗,可以
class Solution {
public int translateNum(int num) {
//因为只需要统计翻译种数,而不需要具体的翻译方案,因此动态规划可以
//dp[i] = dp[i - 1] + dp[i - 2](如果是两位的话)
//从低位到高位,用数字直接处理
int cur = num % 10; //个位
int pre = cur; //前面一位
int res = 1;
int dp1 = 1; //两个状态量,分别记录dp[1]和dp[0]
int dp0 = 1;
//处理十位
num /= 10;
while(num > 0){
cur = num % 10; //当前位数
res = dp1;
//如果能和前一位拼接
if(cur != 0 && cur * 10 + pre <= 25)
res += dp0;
dp0 = dp1;
dp1 = res;
pre = cur;
num /= 10;
}
return res;
}
}
剑指 Offer 47. 礼物的最大价值
题目描述
在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
示例 1:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 12
解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/li-wu-de-zui-da-jie-zhi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
因为只能从左面和上面转移,所以没必要深搜,还是动态规划
另外,多开辟一行一列的空间可以使代码更加简洁,这里就不写了
class Solution {
public int maxValue(int[][] grid) {
//同样是动态规划,因为只能从上面和左面转移过来
int m = grid.length;
int n = grid[0].length;
int[][] dp = new int[m][n];
dp[0][0] = grid[0][0];
for(int i = 1; i < m; i++){
dp[i][0] = grid[i][0] + dp[i - 1][0];
}
for(int j = 1; j < n; j++){
dp[0][j] = grid[0][j] + dp[0][j - 1];
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
}
}
return dp[m - 1][n - 1];
}
}
以上是关于LeetCode1442. 形成两个异或相等数组的三元组数目 / 剑指 Offer 46. 把数字翻译成字符串 / 剑指 Offer 47. 礼物的最大价值的主要内容,如果未能解决你的问题,请参考以下文章
算法leetcode1442. 形成两个异或相等数组的三元组数目(rust真是好用)
算法leetcode1442. 形成两个异或相等数组的三元组数目(rust真是好用)
leetcode1442. 形成两个异或相等数组的三元组数目
LeetCode 1442. 形成两个异或相等数组的三元组数目