本文已参与「新人创作礼」活动,一起开启掘金创作之路。
504. 七进制数
2022.3.7 每日一题
题目描述
给定一个整数 num,将其转化为 7 进制,并以字符串形式输出。
示例 1:
输入: num = 100 输出: "202"
示例 2:
输入: num = -7 输出: "-10"
提示:
-10^7 <= num <= 10^7
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/ba… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
class Solution {
public String convertToBase7(int num) {
if(num == 0)
return "0";
boolean flag = false; //标记正负数
if(num >= 0)
flag = true;
//转成正数
if(!flag) num = -num;
StringBuilder sb = new StringBuilder();
while(num != 0){
sb.append(String.valueOf(num % 7));
num = num / 7;
}
if(!flag)
sb.append("-");
sb.reverse();
return sb.toString();
}
}
2055. 蜡烛之间的盘子
2022.3.8 每日一题,祝所有女性朋友节日快乐,永远年轻快乐
题目描述
给你一个长桌子,桌子上盘子和蜡烛排成一列。给你一个下标从 0 开始的字符串 s ,它只包含字符 '' 和 '|' ,其中 '' 表示一个 盘子 ,'|' 表示一支 蜡烛 。
同时给你一个下标从 0 开始的二维整数数组 queries ,其中 queries[i] = [lefti, righti] 表示 子字符串 s[lefti...righti] (包含左右端点的字符)。对于每个查询,你需要找到 子字符串中 在 两支蜡烛之间 的盘子的 数目 。如果一个盘子在 子字符串中 左边和右边 都 至少有一支蜡烛,那么这个盘子满足在 两支蜡烛之间 。
比方说,s = "|||||" ,查询 [3, 8] ,表示的是子字符串 "||**|" 。子字符串中在两支蜡烛之间的盘子数目为 2 ,子字符串中右边两个盘子在它们左边和右边 都 至少有一支蜡烛。 请你返回一个整数数组 answer ,其中 answer[i] 是第 i 个查询的答案。
示例 1:
输入:s = "||***|", queries = [[2,5],[5,9]] 输出:[2,3] 解释: -queries[0] 有两个盘子在蜡烛之间。 -queries[1] 有三个盘子在蜡烛之间。
示例 2:
输入:s = "*||||||", queries = [[1,17],[4,5],[14,17],[5,11],[15,16]] 输出:[9,0,0,0,0] 解释: -queries[0] 有 9 个盘子在蜡烛之间。 -另一个查询没有盘子在蜡烛之间。
提示:
3 <= s.length <= 10^5 s 只包含字符 '*' 和 '|' 。 1 <= queries.length <= 10^5 queries[i].length == 2 0 <= lefti <= righti < s.length
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/pl… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
二分+前缀和 我这里直接用的TreeMap
class Solution {
public int[] platesBetweenCandles(String s, int[][] queries) {
//我能想到的思路是用一个treemap,键是每个蜡烛的位置,值是右边到下一个蜡烛有多个盘子
//然后查找的时候,先找到左边下标最近(右边)的蜡烛,然后找到右边下标最近(左边)的蜡烛
//然后遍历treemap,把这个范围内的盘子都加起来
//这样的话,因为是离线查询,极限是On方,应该会超时,不过先写一下吧
//不不,应该统计蜡烛左边有多少盘子,这样就和前缀和一样了
int l = s.length();
TreeMap<Integer, Integer> map = new TreeMap<>();
int idx = -1;
int count = 0;
//统计每个蜡烛右边有多少个盘子
for(int i = 0; i < l; i++){
char c = s.charAt(i);
if(c == '|'){
idx = i;
map.put(idx, count);
}else{
count++;
}
}
//查询
int n = queries.length;
int[] res = new int[n];
for(int i = 0; i < n; i++){
int[] temp = queries[i];
if(map.ceilingKey(temp[0]) == null){
res[i] = 0;
continue;
}
int left = map.ceilingKey(temp[0]);
if(map.floorKey(temp[1]) == null){
res[i] = 0;
continue;
}
int right = map.floorKey(temp[1]);
int ll = map.get(left);
int rr = map.get(right);
res[i] = rr - ll;
if(left >= right)
res[i] = 0;
}
return res;
}
}
798. 得分最高的最小轮调
2022.3.9 每日一题
题目描述
给你一个数组 nums,我们可以将它按一个非负整数 k 进行轮调,这样可以使数组变为 [nums[k], nums[k + 1], ... nums[nums.length - 1], nums[0], nums[1], ..., nums[k-1]] 的形式。此后,任何值小于或等于其索引的项都可以记作一分。
例如,数组为 nums = [2,4,1,3,0],我们按 k = 2 进行轮调后,它将变成 [1,3,0,2,4]。这将记为 3 分,因为 1 > 0 [不计分]、3 > 1 [不计分]、0 <= 2 [计 1 分]、2 <= 3 [计 1 分],4 <= 4 [计 1 分]。 在所有可能的轮调中,返回我们所能得到的最高分数对应的轮调下标 k 。如果有多个答案,返回满足条件的最小的下标 k 。
示例 1:
输入:nums = [2,3,1,4,0] 输出:3 解释: 下面列出了每个 k 的得分: k = 0, nums = [2,3,1,4,0], score 2 k = 1, nums = [3,1,4,0,2], score 3 k = 2, nums = [1,4,0,2,3], score 3 k = 3, nums = [4,0,2,3,1], score 4 k = 4, nums = [0,2,3,1,4], score 3 所以我们应当选择 k = 3,得分最高。
示例 2:
输入:nums = [1,3,0,2,4] 输出:0 解释: nums 无论怎么变化总是有 3 分。 所以我们将选择最小的 k,即 0。
提示:
1 <= nums.length <= 10^5 0 <= nums[i] < nums.length
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/sm… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
能直接想到的就是超时的方法,统计每个位置可以移动的次数,然后找到使分数最高的次数
class Solution {
public int bestRotation(int[] nums) {
//就是旋转数组,然后看哪个数组分最高
//统计每一个数,在哪几个位置是满足条件的,然后将需要移动多少次,放在一个set集合中
//因为最多移动长度减1次,所以统计哪一次分最高,然后输出这个最高分
//例如第一个例子,2可以向左移动1,2,3次,3移动2,3次,1需要向左移动1 3 4次,4需要4次,0需要0 1 2 3 4次
//那么可以看到,移动3次是最优选择,因为有4分
int l = nums.length;
Map<Integer, List<int[]>> map = new HashMap<>();
for(int i = 0; i < l; i++){
int t = nums[i];
List<int[]> list = new ArrayList<>();
//如果t大于下标i,那么需要移动到t到length - 1的位置,也就是说,需要移动i+1到i+1+length-1-t次
if(t > i){
list.add(new int[]{(i + 1) % l, (i + l - t) % l});
//如果小于等于的时候,分两段
//例如示例1中的1,那么比它大的位置肯定是满足条件的,就和上面情况相同,比它小的位置,也就是t到i,也是满足条件的
}else{
if(i + 1 <= l - 1)
list.add(new int[]{(i + 1) % l, l - 1});
list.add(new int[]{0, i - t});
}
/*
System.out.println(list.get(0)[0] + "+++");
System.out.println(list.get(0)[1]);
if(list.size() > 1){
System.out.println(list.get(1)[0] + "---");
System.out.println(list.get(1)[1] + "--------");
}*/
map.put(i, list);
}
int max = 0;
int count = 0;
//当移动这么多次时,几个满足条件
for(int i = 0; i < l; i++){
int m = 0;
for(int t : map.keySet()){
List<int[]> list = map.get(t);
int[] t1 = list.get(0);
if(i >= t1[0] && i <= t1[1])
m++;
else if(list.size() > 1){
int[] t2 = list.get(1);
if(i >= t2[0] && i <= t2[1])
m++;
}
}
if(m > max){
max = m;
count = i;
}
}
return count;
}
}
那么怎么做改进呢 我们通过一次遍历,得到了每个位置可以移动的次数范围 知道这个范围以后,可以通过差分数组来实现对次数的统计 具体来说,对于一个数x,如果它移动的范围(即可以得分)是[left,right] 那么利用差分数组的思想,先创建一个差分数组diff[],然后令diff[left] + 1,令diff[right + 1] - 1 意思是到left这个位置,分数开始加1,到right+1这个位置,分数开始-1 然后计算这个差分数组的前缀和,就可以得到向左移动几次,得到的分数最高了
class Solution {
public int bestRotation(int[] nums) {
//就是旋转数组,然后看哪个数组分最高
//统计每一个数,在哪几个位置是满足条件的,然后将需要移动多少次,放在一个set集合中
//因为最多移动长度减1次,所以统计哪一次分最高,然后输出这个最高分
//例如第一个例子,2可以向左移动1,2,3次,3移动2,3次,1需要向左移动1 3 4次,4需要4次,0需要0 1 2 3 4次
//那么可以看到,移动3次是最优选择,因为有4分
int l = nums.length;
Map<Integer, List<int[]>> map = new HashMap<>();
for(int i = 0; i < l; i++){
int t = nums[i];
List<int[]> list = new ArrayList<>();
//如果t大于下标i,那么需要移动到t到length - 1的位置,也就是说,需要移动i+1到i+1+length-1-t次
if(t > i){
list.add(new int[]{(i + 1) % l, (i + l - t) % l});
//如果小于等于的时候,分两段
//例如示例1中的1,那么比它大的位置肯定是满足条件的,就和上面情况相同,比它小的位置,也就是t到i,也是满足条件的
}else{
if(i + 1 <= l - 1)
list.add(new int[]{(i + 1) % l, l - 1});
list.add(new int[]{0, i - t});
}
/*
System.out.println(list.get(0)[0] + "+++");
System.out.println(list.get(0)[1]);
if(list.size() > 1){
System.out.println(list.get(1)[0] + "---");
System.out.println(list.get(1)[1] + "--------");
}*/
map.put(i, list);
}
int[] diff = new int[l + 1];
for(int i = 0; i < l; i++){
List<int[]> list = map.get(i);
int[] t1 = list.get(0);
diff[t1[0]]++;
diff[t1[1] + 1]--;
if(list.size() > 1){
int[] t2 = list.get(1);
diff[t2[0]]++;
diff[t2[1] + 1]--;
}
}
int max = 0;
int count = 0;
int score = 0;
//当移动这么多次时,几个满足条件
for(int i = 0; i < l; i++){
score += diff[i];
if(score > max){
max = score;
count = i;
}
}
return count;
}
}
官解将分成两段的情况也合并成一段了,其实不太好理解