赞
踩
思路:非常简单的模拟题,先把数字给取出来,然后三个三个拼接,最后只剩四维的时候在分别讨论即可。
class Solution { public String reformatNumber(String number) { StringBuffer res = new StringBuffer(); StringBuffer s = new StringBuffer(); for(int i = 0;i < number.length();i++) { if(Character.isDigit(number.charAt(i))) { s.append(number.charAt(i)); } } int n = s.length(); for(int i = 0;i < n;i += 3) { if(n - i <= 4) { if(n-i == 2) { res.append(s.substring(i,i+2)); } else if(n-i == 3) { res.append(s.substring(i,i+3)); } else if(n-i == 4) { res.append(s.substring(i,i+2)); res.append("-"); res.append(s.substring(i+2,i+4)); } } else { res.append(s.substring(i,i+3)); res.append("-"); } } return res.toString(); } }
思路:第一感觉就是双指针,模拟删除数组的所有可能。简单来说就是先遍历每一个下标,该下标表示删除的子数组以当前下标为结尾,那么因为每个元素的都是大于0的,所以希望左边界越小越好。
那么怎么确定左边界呢?如果一个数组是不重复的,比如:[1,2,3,4]
,那么删除所有的元素即可。如果有重复,如[4,5,1,3,4]
,那么左边界就可以取到当前数字上次出现的位置。还有一种情况,[4,5,1,2,5,4]
,如果当前遍历到了最后一个元素,那么上次出现4
的位置中间依旧存在重复元素。所以在遍历右边界过程中,左边界只能一直增大或不变,而不能减小。遍历完有边界之后,取过程中出现的最大值即可。
class Solution { public int maximumUniqueSubarray(int[] nums) { int n = nums.length; int[] sum = new int[n]; //前缀和数组,用来来取一段连续区间的值 for(int i = 0;i < n;i++) { sum[i] = nums[i]; if(i > 0) sum[i] += sum[i-1]; } //Map记录每个数字上次出现的位置 Map<Integer, Integer> map = new HashMap<>(); int start = -1,res = 0; for(int i = 0;i < n;i++) { int lastPos = map.getOrDefault(nums[i] , -1); // 左边界只能增大或者不变 start = Math.max(start, lastPos); int cur = sum[i] - (start >= 0 ? sum[start] : 0); res = Math.max(res, cur); map.put(nums[i],i); } return res; } }
思路:动态规划 + 优先队列。考虑每一个下标
i
,表示跳到当前位置的最大得分,而我们只能从与i
距离不超过k
的位置跳过来。如果考虑遍历i
前面的k
个位置的最大得分,就会超时。所以这时候,选择用优先队列,存储两个值,一个是某个位置上的得分,另一个是该得分所在的位置。
遍历到每一个i
位置时,考虑优先队列的队首元素,如果队首元素的位置与当前位置已经超过k
,那么之后也一定超过k
,所以不再考虑,直接弹出。重复以上操作,直至队列为空,或队首元素的位置与当前位置小于k
,那么该队首元素位置的得分一定是能够跳到i
位置的最大得分(因为优先队列)。
class Solution { public int maxResult(int[] nums, int k) { PriorityQueue<Integer[]> q = new PriorityQueue<>(new Comparator<Integer[]>() { @Override public int compare(Integer[] o1, Integer[] o2) { if(o1[0] != o2[0]) { return o2[0] - o1[0]; } return o2[1] - o1[1]; } }); int n = nums.length,res = 0; for(int i = 0;i < n;i++) { int Mx = 0; while(q.size() > 0) { Integer[] c = q.peek(); int v = c[0], idx = c[1]; // 如果和当前位置距离超过K,则弹出;否则队首元素的得分就是最大值。 if(i-idx > k) { q.poll(); continue; } else { Mx = v; break; } } q.offer(new Integer[]{Mx + nums[i],i}); if(i == n-1) res = Mx + nums[i]; } return res; } }
思路 (该思路出自讨论区,我也是从这里学习到解题思路的):先分别对询问和边权进行排序,然后依次回答询问,每次回答询问前,将所有小于询问边权的边加入图中,然后判定联通性。
由于这里询问的边权进行了排序,所以只需要不断往图中加边,而不需要删边,判断连通性用并查集即可。
const int maxn = 1e5 + 10; int pre[maxn]; //====================并查集模板============================= //查找上级 int find_pre(int x) { int r = pre[x]; while(pre[r] != r) { r = pre[r]; } //路径压缩 while(x != r) { int tmp = pre[x]; pre[x] = r; x = tmp; } return r; } //合并 void join(int x,int y) { int fx = find_pre(x); int fy = find_pre(y); if(fx == fy) return; if (fx > fy) swap(fx, fy); pre[fx] = fy; } void init(int n) { for(int i = 0;i <= n;i++) { pre[i] = i; } } //====================并查集模板============================= struct Node { int u,v; int limit; int idx; } query[maxn]; bool cmp(Node a, Node b) { return a.limit < b.limit; } class Solution { public: vector<bool> distanceLimitedPathsExist(int N, vector<vector<int>>& e, vector<vector<int>>& queries) { int n = e.size(), m = queries.size(); vector<bool> res(m); init(N); for(int i = 0;i < m;i++) { query[i].u = queries[i][0]; query[i].v = queries[i][1]; query[i].limit = queries[i][2]; query[i].idx = i; } sort(e.begin(), e.end(), [&](auto& e1, auto& e2) { return e1[2] < e2[2]; }); sort(query, query + m, cmp); for(int i = 0,j = 0;i < m;i++) { //查询前,先把小于限制边权的边加入图中 while(j < n && e[j][2] < query[i].limit) { join(e[j][0],e[j][1]); j++; } // 判断连通性 int fu = find_pre(query[i].u); int fv = find_pre(query[i].v); if(fu == fv) { res[query[i].idx] = true; } else { res[query[i].idx] = false; } } return res; } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。