No.1重新格式化电话号码
解题思路
预处理两种特殊符号之后的字符串根据长度 len 分一下三种情况
len % 3 == 0: 直接拼接
len % 3 == 1: 保留最后四位特殊拼接
len % 3 == 2: 保留最后两位特殊拼接
代码展示
class Solution {
public String reformatNumber(String number) {
if (number == null || number.length() == 0) {
return "";
}
int n = number.length();
StringBuilder tempString = new StringBuilder();
for (int i = 0; i < n; i++) {
char c = number.charAt(i);
if (c == '-' || c == ' ') {
continue;
}
tempString.append(c);
}
int tmpSize = tempString.length();
StringBuilder resString = new StringBuilder();
if (tmpSize % 3 == 0) {
for (int i = 0; i < tmpSize; i += 3) {
resString.append(tempString.charAt(i))
.append(tempString.charAt(i + 1))
.append(tempString.charAt(i + 2));
if (i != tmpSize - 3) {
resString.append('-');
}
}
return resString.toString();
}
else if (tmpSize % 3 == 1) {
int tmpL = tmpSize - 4;
for (int i = 0; i < tmpL; i += 3) {
resString.append(tempString.charAt(i))
.append(tempString.charAt(i + 1))
.append(tempString.charAt(i + 2))
.append('-');
}
resString.append(tempString.charAt(tmpL))
.append(tempString.charAt(tmpL + 1))
.append('-')
.append(tempString.charAt(tmpL + 2))
.append(tempString.charAt(tmpL + 3));
return resString.toString();
}
else {
int tmpL = tmpSize - 2;
for (int i = 0; i < tmpL; i += 3) {
resString.append(tempString.charAt(i))
.append(tempString.charAt(i + 1))
.append(tempString.charAt(i + 2))
.append('-');
}
resString.append(tempString.charAt(tmpL))
.append(tempString.charAt(tmpL + 1));
return resString.toString();
}
}
}
No.2 删除子数组的最大得分
解题思路
同向双指针经典应用
left 指针枚举起点
right指针不断的扩大sunArray的范围
当不满足条件时,移动left指针使得满足条件
代码展示
public int maximumUniqueSubarray(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int n = nums.length;
int res = 0;
int tmpSum = 0;
// two point
// 枚举左端点left,右端点right,记录left ~ right 之间重复字符个数
int left = 0, right = 0;
int []counts = new int[10001];
while (left < n && right < n) {
int num = nums[right];
counts[num] += 1;
tmpSum += num;
// subArray 存在重复数字,从left开始移除,直到满足条件
while (left < n && counts[num] > 1) {
tmpSum -= nums[left];
counts[nums[left]] -= 1;
left++;
}
res = Math.max(res, tmpSum);
right++;
}
return res;
}
No.3跳跃游戏 VI
解题思路
动态规划加优先队列
数据结构Pair,当前位置的结果值value,当前位置的index
优先队列的堆首是已经到达过位置结果值最大的
判断队首的位置能否调达至当前位置i
代码展示
class Solution {
static class Pair {
int value;
int index;
Pair(int value, int index) {
this.value = value;
this.index = index;
}
}
public int maxResult(int[] nums, int k) {
if (nums == null || nums.length == 0) {
return 0;
}
int n = nums.length;
// 单调队列【优先队列】
PriorityQueue
queue.offer(new Pair(nums[0], 0));
int res = nums[0];
for (int i = 1; i < n; i++) {
// 选择一个可到达的目的地中最大的那个跳跃,不满足则出队列
while (!queue.isEmpty() && i - queue.peek().index > k) {
queue.poll();
}
if (!queue.isEmpty()) {
res = queue.peek().value + nums[i];
}
queue.offer(new Pair(res, i));
}
return res;
}
}
No.4 检查边长度限制的路径是否存在
解题思路
查询按照距离限制排序,记录在TreeMap,query => index
边集合根据边权重排序
针对每一个查询
只构建边权重小于limit的边
判断查询的点是否连通
代码展示
// 并查集模板
static class UnionFind {
int[] father;
UnionFind(int n) {
father = new int[n];
for (int i = 0; i < n; i++) {
father[i] = i;
}
}
public int find(int x) {
if (x == father[x]) {
return x;
}
return father[x] = find(father[x]);
}
public void union(int a, int b) {
int fatherA = find(a);
int fatherB = find(b);
if (fatherA != fatherB) {
father[fatherA] = fatherB;
}
}
}
public boolean[] distanceLimitedPathsExist(int n, int[][] edgeList, int[][] queries) {
// key:query[start, end, limit] value: index
// 按照距离远近排序,距离从小到大
TreeMap
for (int i = 0; i < queries.length; i++) {
map.put(queries[i], i);
}
// 图的边集合也根据边的权重排序
Arrays.sort(edgeList, Comparator.comparingInt(o -> o[2]));
boolean[] res = new boolean[queries.length];
UnionFind unionFind = new UnionFind(n);
int index = 0;
while (!map.isEmpty()) {
Map.Entry
int[] query = curr.getKey();
int currIn = curr.getValue();
// 只连接比limit更小的那些边
while (index < edgeList.length && edgeList[index][2] < query[2]) {
unionFind.union(edgeList[index][0], edgeList[index][1]);
index++;
}
// 查询两端点是否连通
res[currIn] = (unionFind.find(query[0]) == unionFind.find(query[1]));
}
return res;
}