力扣第245场周赛

今天的第二题得用二分加数组写,拿HashSet写不太友好呀。

LeetCode 5784. 重新分配字符使所有字符串都相等

本题链接

这道题简单题一般就是暴力,也不会太为难你,但是不要那么老实的镇区写暴力,这道题带点贪心的意思,反正是移动,最后的结果只要每一个字符的值mod个数==0的话就返回true,否则返回false。

class Solution {
    public boolean makeEqual(String[] words) {
        int[] arr = new int[26];
        int n = words.length;
        for(String s: words){
            char[] c = s.toCharArray();
            for(char ch: c){
                arr[ch-'a']++;
            }
        }
        for(int i = 0; i < 26; i++){
            if(arr[i]%n!=0){
                return false;
            }
        }
        return true;
    }
}

LeetCode 5786. 可移除字符的最大数目

这道题卡的很恶心,主要用到了两个知识点:二分和子序列
下面先贴一下模板:
最小值最大:

//check(mid)是对mid处的数进行判断。
//若符合right,答案就在left。即binarySearch1
//若符合left,答案就在right。即binarySearch2

int binarySearch1(int l,int r){
    while(l < r){
        int mid = l + (r - 1) / 2;      //mid那里不+1
        if(check(mid)) r = mid;         //先r
        else l = mid + 1;                //后l l+1
    }
    return l;                           //二分到最后一个,即l==r时,为所求
}

int binarySearch2(int l,int r){
    while(l < r){
        int mid = l + (r - l) / 2 + 1;  //mid那里要+1 
        if(check(mid)) l = mid;         //先l
        else r = mid - 1;               //后r  r-1    
    }
    return l;                           //二分到最后一个,即l==r时,为所求
}

子序列

import java.util.*;
class Main{
    public static void main(String []args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[] arr = new int[n];
        int[] nums = new int[m];
        for(int i = 0; i < n; i++){
            arr[i] = sc.nextInt();
        }
        for(int i = 0; i < m; i++){
            nums[i] = sc.nextInt();
        }
        int res = 0,j = 0;
        for(int i = 0; i < m; i++){
            if(j < n &&arr[j]==nums[i]){
                j++;
            }

        }
        if(j==n){
                System.out.println("Yes");
        }else{        
            System.out.println("No");
        }
    }
}

本题解法:

class Solution {
    boolean[] st = new boolean[100010];
    public int maximumRemovals(String s, String p, int[] removable) {
        int l = 0,r = removable.length;
        while(l < r){
            int mid = (l+r+1)/2;
            if(check(mid,s,p,removable)){
                l = mid;
            }else{
                r = mid - 1;
            }
        }
        return l;

    }
    boolean check(int mid,String s,String p,int[] re){
        Arrays.fill(st,false);
        for(int i = 0; i < mid;i++){
            st[re[i]] = true;
        }
        int j = 0;
        for(int i = 0; i < s.length(); i++){
            if(st[i]){
                continue;
            }
            if(j < p.length()&& s.charAt(i)==p.charAt(j)){
                j++;
            }
        }
        return j == p.length();
    }
}

LeetCode 5785. 合并若干三元组以形成目标三元组

这道题是一个贪心题,先看数据范围10的5次方,因此不是个贪心就是个DP。显而易见是个贪心,因此先把>= 目标数组对应位置的数组去掉,然后判断对应位置上有没有目标数组的值。

	class Solution {
    public boolean mergeTriplets(int[][] triplets, int[] target) {
        
        ArrayList<int[]> list = new ArrayList<>();
        for(int[] arr: triplets){
            boolean flag = false;
            for(int i = 0; i < 3; i++){
                if(arr[i]>target[i]){
                    flag = true;
                }
            }
            if(!flag&&(arr[0] == target[0]||arr[1] == target[1]||arr[2] == target[2])){
                list.add(arr);
            }
        }
        if(list.size()==0){
            return false;
        }
        boolean[] flag = new boolean[3];
        for(int[] arr:list){
            for(int i = 0; i < 3; i++){
                if(arr[i] ==target[i]){
                    flag[i] = true;
                }
            }
        }
        for(int i = 0; i < 3; i++){
            if(!flag[i]){
                return false;
            }
        
        }
        return true;
    }
}

5787. 最佳运动员的比拼回合

本题较难,参考题解:
定义 \textit{dp}(n,\textit{fi},\textit{se})dp(n,fi,se) 为人数为 nn,两名选手位置分别在 \textit{fi}fi 和 \textit{se}se 时的最早回合数和最晚回合数。
转移时,枚举下一轮两名选手的位置。
为简化判断,可以在枚举前处理一下两名选手的位置:若两名选手均在中间位置右侧,或者第二名选手比第一名选手更靠近端点,则将第一名选手的位置映射到第二名选手关于中间位置对称的位置,第二名选手同理。这样交换后,第一名选手必位于中间位置左侧,且第一名选手比第二名选手更靠近端点。
然后枚举第一名选手左侧保留多少个人,以及第一名选手和第二名选手中间保留多少个人,这样就可以得到下一轮两名选手的位置。
作者:endlesscheng


class Solution {
	int[][][][] map;
	void walk(int n, int p1, int p2, int p11, int p21, int index, int[] res) {
		if(index + index >= n-1) {
			int[] r = solve((n+1)>>>1, p11, p21);
			res[0] = Math.min(res[0], r[0]);
			res[1] = Math.max(res[1], r[1]);
		} else {
			int index2 = n-1-index;
			int m = 0; 
			if(index != p1 && index != p2) {
				if(index < p1) {
					walk(n, p1, p2, p11-1, p21-1, index+1, res);
					m = 1;
				}else if(index < p2) {
					walk(n, p1, p2, p11, p21-1, index+1, res);
					m = 2;
				} else {
					walk(n, p1, p2, p11, p21, index+1, res);
					m = 3;
				}
			}
			if(index2 != p1 && index2 != p2) {
				if(index2 < p1) {
					if(m != 1)
						walk(n, p1, p2, p11-1, p21-1, index+1, res);
				} else if(index2 < p2) {
					if(m != 2)
						walk(n, p1, p2, p11, p21-1, index+1, res);
				} else {
					if(m != 3)
						walk(n, p1, p2, p11, p21, index+1, res);
				}
					
			}
		}
	}
	int[] solve(int n, int p1, int p2) {
		int[] res = map[n][p1][p2];
		if(res != null)
			return res;
		if(p1 + p2 == n-1) {
			res = new int[] {1,1};
		} else {
			res = new int[] {n, 0};
			walk(n, p1, p2, p1, p2, 0, res);
			res[0] ++;
			res[1] ++;
		}
		map[n][p1][p2] = res;
		return res;
	}
	//..p1..p2..
	//
    public int[] earliestAndLatest(int n, int p1, int p2) {
    	p1--;
    	p2--;
    	if(p1 > p2) {
    		int x = p1;
    		p1=p2;
    		p2 = x;
    	}
    	this.map = new int[n+1][n][n][];
    	return solve(n, p1, p2);
    }
}

你可能感兴趣的:(算法,leetcode,算法,面试,数据结构)