力扣 2020-12-20 第 220 场周赛思路

2020-12-20 第 220 场周赛

5629. 重新格式化电话号码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ug1kstqx-1608442316936)(image-20201220130229157.png)]

思路:非常简单的模拟题,先把数字给取出来,然后三个三个拼接,最后只剩四维的时候在分别讨论即可。

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();
    }
}

5630. 删除子数组的最大得分

在这里插入图片描述

思路:第一感觉就是双指针,模拟删除数组的所有可能。简单来说就是先遍历每一个下标,该下标表示删除的子数组以当前下标为结尾,那么因为每个元素的都是大于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;
    }
}

5631. 跳跃游戏 VI

在这里插入图片描述

思路:动态规划 + 优先队列。考虑每一个下标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;
    }
}

5632. 检查边长度限制的路径是否存在

在这里插入图片描述

思路 (该思路出自讨论区,我也是从这里学习到解题思路的):先分别对询问和边权进行排序,然后依次回答询问,每次回答询问前,将所有小于询问边权的边加入图中,然后判定联通性。

由于这里询问的边权进行了排序,所以只需要不断往图中加边,而不需要删边,判断连通性用并查集即可。

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;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值