T1直接暴力枚举所有k长度的区间,统计出修改的最小次数。
T2 调用Java String的replaceAll(String a, String b)方法秒杀
class Solution {
public int secondsToRemoveOccurrences(String s) {
int res=0;
while(s.contains("01")){
res++;
s=s.replaceAll("01","10");
}
return res;
}
}
这题我是废了脑力的,刚开始想直接暴力,遍历shifts中的所有区间,把移位总数全部统计出来,最后进行移位,直接TLE,才发现这有可能是O(N^2)
的时间复杂度。刚好前几天的每日一题,看到宫水三叶大佬提到了差分法,我的另一篇文章算法学习-差分也进行了整理,这道题就是满足「区间修改,单点查询」的性质,因此可以采用差分法做。
class Solution {
public String shiftingLetters(String s, int[][] shifts) {
int len=s.length();
int[]c=new int[len+1];
int[]change=new int[len];
for(int[]sh:shifts){
int start=sh[0],end=sh[1],v=sh[2];
c[start]+=v==0?-1:1;
c[end+1]+=v==0?1:-1;
}
change[0]=c[0];
for(int i=1;i<len;i++){
change[i]=change[i-1]+c[i];
}
StringBuilder sb=new StringBuilder();
for(int i=0;i<len;i++){
int shiftnum=change[i]%26;
int temp=s.charAt(i)+shiftnum;
if(temp<'a'){
temp='z'-(Math.abs(temp-'a')-1);
}
if(temp>'z'){
temp='a'+(Math.abs(temp-'z')-1);
}
sb.append((char)temp);
}
return sb.toString();
}
}
其中可以简化的点是,差分数组的求和可以放在最后遍历改变字符串s
的循环中,同时这种循环移位(即z
右移变为a
,a
左移变为z
)也可以进行简化,即计算相对于a
的偏移量:
class Solution {
public String shiftingLetters(String s, int[][] shifts) {
int len=s.length();
int[]c=new int[len+1];
int[]change=new int[len];
for(int[]sh:shifts){
int start=sh[0],end=sh[1],v=sh[2];
c[start]+=v==0?-1:1;
c[end+1]+=v==0?1:-1;
}
StringBuilder sb=new StringBuilder();
for(int i=0,shiftNum=0;i<len;i++){
shiftNum+=c[i];
int gap=s.charAt(i)-'a';
//+26可以让负数变为相对于'a'的正数,对于正数却无影响
int newGap=((gap+shiftNum)%26+26)%26;
char res=(char)(newGap+'a');
sb.append(res);
}
return sb.toString();
}
}
在计算循环移位字母的时候下面的trick
可以重点记住:
int newGap=((gap+shiftNum)%26+26)%26;
进行推广,如果一个长度为n
的数组,假定当前下标为i
,我们对其向左进行k
次「旋转」,最后的下标为:
(i-k+n)%n
看大佬的解法,是并查集的套路题,然而并查集我只草草做了下,如今连模板也不会默写了,看来又是埋坑并查集专题了,连着前两次周赛的数位dp专题和图的深搜专题再次埋坑。贴下灵神的题解。
这场周赛整个就是掉分状态,做完第一题直接开始摆烂,第二题感觉可以贪心做,但是又不知道如何使得最终结果是回文串。第三题我先建图,然后尝试用深搜做,但是深搜实在不太熟练,不清楚应该怎么记录搜索次数以及base条件。第四题一眼堆,但我也不会堆,整个就是一个坐牢。
T1直接从前往后模拟就好
直接贪心做法,将回文数字看成前半部分和前半部分的翻转拼接而成(相对于偶数而言,奇数只需要在中间加一个数字就行),长度越长,前半部分的数字越大,最后的回文数字越大。我们只需要先将1-9有偶数个个数的数字尽可能的构成前半部分(因为有偶数个数,所以后半部分反转数字也可以和他对称),同时考虑到不能包含前导0,因此只有当前半部分长度不为0时,才可以加入0。在把偶数对都用完的情况下,就看是否还可以在中间加一个数字,从9-1里面挑个最大的夹在中间。
全为0的时候要进行特判返回“0”
。
class Solution {
public String largestPalindromic(String num) {
int[]cnt=new int[10];
int len=num.length();
for(int i=0;i<len;i++){
cnt[num.charAt(i)-'0']++;
}
//全为0的时候需要进行特判
if(cnt[0]==len) return "0";
//构成前半部分
StringBuilder sb=new StringBuilder();
for(int i=9;i>=1;i--){
sb.append(String.valueOf(i).repeat(cnt[i]/2));
}
//判断是否可以加入0
if(sb.length()>0) sb.append(String.valueOf(0).repeat(cnt[0]/2));
//得到反转的后半部分,但需要new StringBuilder(sb),否则将前半部分也反转了
StringBuilder sbreverse=new StringBuilder(sb).reverse();
for(int i=9;i>=0;i--){
if(cnt[i]%2!=0){
sb.append(i);
break;
}
}
sb.append(sbreverse);
return sb.toString();
}
}
做题的时候就想着两次DFS,第一次递归建立无向图,第二次遍历增加圈数,但是觉得自己无法实现每圈都能找出所有节点,其实就采用类似层序遍历的方法,每次将队列中的节点全部弹出,将相邻节点入栈,由于是无向图,而不是从根到叶子节点有方向的树,所以得做好标记不要重复访问,数组标记或者Set标记都可以。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
HashMap<Integer,HashSet<Integer>> map;
public int amountOfTime(TreeNode root, int start) {
map=new HashMap<>();
buildGraph(root);
HashSet<Integer> vis=new HashSet<>();
Deque<Integer> que=new ArrayDeque<>();
que.offer(start);
vis.add(start);
int res=-1;
while(!que.isEmpty()){
res++;
int size=que.size();
for(int i=0;i<size;i++){
int top=que.poll();
HashSet<Integer>set=map.get(top);
if(set==null) continue;
for(int node:set){
//不重复访问
if(vis.contains(node)) continue;
vis.add(node);
que.offer(node);
}
}
}
return res;
}
public void buildGraph(TreeNode root){
if(root==null) return;
if(root.left!=null){
HashSet<Integer> set1=map.getOrDefault(root.val,new HashSet<Integer>());
HashSet<Integer> set2=map.getOrDefault(root.left.val,new HashSet<Integer>());
set1.add(root.left.val);
set2.add(root.val);
map.put(root.val,set1);
map.put(root.left.val,set2);
}
if(root.right!=null){
HashSet<Integer> set1=map.getOrDefault(root.val,new HashSet<Integer>());
HashSet<Integer> set2=map.getOrDefault(root.right.val,new HashSet<Integer>());
set1.add(root.right.val);
set2.add(root.val);
map.put(root.val,set1);
map.put(root.right.val,set2);
}
buildGraph(root.left);
buildGraph(root.right);
}
}
这题一眼就是用堆做,但无奈自己堆相关的题目实在做得少,先把灵神的题解贴下,堆的专题也得安排起来了呀。