Leetcode 第173场周赛题解

5319. 删除回文子序列

题目描述

给你一个字符串 s,它仅由字母 'a' 和 'b' 组成。每一次删除操作都可以从 s 中删除一个回文 子序列。

返回删除给定字符串中所有字符(字符串为空)的最小删除次数。

「子序列」定义:如果一个字符串可以通过删除原字符串某些字符而不改变原字符顺序得到,那么这个字符串就是原字符串的一个子序列。

「回文」定义:如果一个字符串向后和向前读是一致的,那么这个字符串就是一个回文。

示例 1:

输入:s = "ababa"
输出:1
解释:字符串本身就是回文序列,只需要删除一次。
示例 2:

输入:s = "abb"
输出:2
解释:"abb" -> "bb" -> "". 
先删除回文子序列 "a",然后再删除 "bb"。
示例 3:

输入:s = "baabb"
输出:2
解释:"baabb" -> "b" -> "". 
先删除回文子序列 "baab",然后再删除 "b"。
示例 4:

输入:s = ""
输出:0
 

提示:

0 <= s.length <= 1000
s 仅包含字母 'a'  和 'b'

分析

这个题目,我觉得在leetcode第一题里面算是复杂的,解法不是一眼就能看到的(也可能是我太菜了,hhh)。当然,仔细分析一下也是很好解的。我们使用两个指针,left和right分别指向序列的两边,同时使用一个visited数组去维护所有已经被访问,并满足s[left]==s[right]的位置。我们要求的答案,就是我们要进行多少次上述过程,才能把序列中的所有位置访问到。

代码

class Solution {
    public int removePalindromeSub(String s) {
        boolean[] visited = new boolean[s.length()];
        int res = 0;
        int count = 0;
        while(count<s.length())
        {
            int left = 0;
            int right = s.length()-1;
            while(visited[left])
            {
                left++;
            }
            while(visited[right])
            {
                right--;
            }
            while(left<=right)
            {
                while(s.charAt(left)!=s.charAt(right))
                {
                    right--;
                }
                visited[left] = true;
                visited[right] = true;
                if(left==right)
                {
                    count++;
                }
                else
                {
                    count+=2;
                }
                left++;
                right--;
            }
            res+=1;
        }
        return res;
    }
}

5320. 餐厅过滤器

题目描述

给你一个餐馆信息数组 restaurants,其中  restaurants[i] = [idi, ratingi, veganFriendlyi, pricei, distancei]。你必须使用以下三个过滤器来过滤这些餐馆信息。

其中素食者友好过滤器 veganFriendly 的值可以为 true 或者 false,如果为 true 就意味着你应该只包括 veganFriendlyi 为 true 的餐馆,为 false 则意味着可以包括任何餐馆。此外,我们还有最大价格 maxPrice 和最大距离 maxDistance 两个过滤器,它们分别考虑餐厅的价格因素和距离因素的最大值。

过滤后返回餐馆的 id,按照 rating 从高到低排序。如果 rating 相同,那么按 id 从高到低排序。简单起见, veganFriendlyi 和 veganFriendly 为 true 时取值为 1,为 false 时,取值为 0 。

示例 1:

输入:restaurants = [[1,4,1,40,10],[2,8,0,50,5],[3,8,1,30,4],[4,10,0,10,3],[5,1,1,15,1]], veganFriendly = 1, maxPrice = 50, maxDistance = 10
输出:[3,1,5] 
解释: 
这些餐馆为:
餐馆 1 [id=1, rating=4, veganFriendly=1, price=40, distance=10]
餐馆 2 [id=2, rating=8, veganFriendly=0, price=50, distance=5]
餐馆 3 [id=3, rating=8, veganFriendly=1, price=30, distance=4]
餐馆 4 [id=4, rating=10, veganFriendly=0, price=10, distance=3]
餐馆 5 [id=5, rating=1, veganFriendly=1, price=15, distance=1] 
在按照 veganFriendly = 1, maxPrice = 50 和 maxDistance = 10 进行过滤后,我们得到了餐馆 3, 餐馆 1 和 餐馆 5(按评分从高到低排序)。 
示例 2:

输入:restaurants = [[1,4,1,40,10],[2,8,0,50,5],[3,8,1,30,4],[4,10,0,10,3],[5,1,1,15,1]], veganFriendly = 0, maxPrice = 50, maxDistance = 10
输出:[4,3,2,1,5]
解释:餐馆与示例 1 相同,但在 veganFriendly = 0 的过滤条件下,应该考虑所有餐馆。
示例 3:

输入:restaurants = [[1,4,1,40,10],[2,8,0,50,5],[3,8,1,30,4],[4,10,0,10,3],[5,1,1,15,1]], veganFriendly = 0, maxPrice = 30, maxDistance = 3
输出:[4,5]
 

提示:

1 <= restaurants.length <= 10^4
restaurants[i].length == 5
1 <= idi, ratingi, pricei, distancei <= 10^5
1 <= maxPrice, maxDistance <= 10^5
veganFriendlyi 和 veganFriendly 的值为 0 或 1 。
所有 idi 各不相同。
在真实的面试中遇到过这道题?

分析

这个题目非常简单,就是考察对于编程语言的应用,实现对象排序。在Java中,我们要继承Comparable接口,实现compareTo方法,直接调用Collections.sort()即可。

代码

class Solution {
    
    class Restaurant implements Comparable<Restaurant>{
        int id;
        int rating;
        int veganFriendly;
        int price;
        int distance;
        Restaurant(int id, int rating, int veganFriendly, int price, int distance){
            this.id = id;
            this.rating = rating;
            this.veganFriendly = veganFriendly;
            this.price = price;
            this.distance = distance;
        }
        
        @Override
        public int compareTo(Restaurant r)
        {
            if(r.rating!=this.rating)
            {
                return r.rating-this.rating;
            }
            else
            {
                return r.id - this.id;   
            }
        }
    }
    public List<Integer> filterRestaurants(int[][] restaurants, int veganFriendly, int maxPrice, int maxDistance) {
        ArrayList<Restaurant> rs = new ArrayList<Restaurant>();
        for(int i=0;i<restaurants.length;i++)
        {
            int id = restaurants[i][0];
            int rating = restaurants[i][1];
            int veganF = restaurants[i][2];
            int price = restaurants[i][3];
            int distance = restaurants[i][4];
            if(veganFriendly==0)
            {
                if(price<=maxPrice&&distance<=maxDistance)
                {
                    Restaurant r = new Restaurant(id ,rating, veganF, price, distance);
                    rs.add(r);
                }
            }
            else
            {
                if(veganF==1&&price<=maxPrice&&distance<=maxDistance)
                {
                    Restaurant r = new Restaurant(id ,rating, veganF, price, distance);
                    rs.add(r);
                }
            }
        }
        Collections.sort(rs);
        ArrayList<Integer> res = new ArrayList<Integer>();
        for(Restaurant r:rs)
        {
            res.add(r.id);
        }
        return res;
    }
}

5321. 阈值距离内邻居最少的城市

题目描述

有 n 个城市,按从 0 到 n-1 编号。给你一个边数组 edges,其中 edges[i] = [fromi, toi, weighti] 代表 fromi 和 toi 两个城市之间的双向加权边,距离阈值是一个整数 distanceThreshold。

返回能通过某些路径到达其他城市数目最少、且路径距离 最大 为 distanceThreshold 的城市。如果有多个这样的城市,则返回编号最大的城市。

注意,连接城市 i 和 j 的路径的距离等于沿该路径的所有边的权重之和。

示例 1:

输入:n = 4, edges = [[0,1,3],[1,2,1],[1,3,4],[2,3,1]], distanceThreshold = 4
输出:3
解释:城市分布图如上。
每个城市阈值距离 distanceThreshold = 4 内的邻居城市分别是:
城市 0 -> [城市 1, 城市 2] 
城市 1 -> [城市 0, 城市 2, 城市 3] 
城市 2 -> [城市 0, 城市 1, 城市 3] 
城市 3 -> [城市 1, 城市 2] 
城市 0 和 3 在阈值距离 4 以内都有 2 个邻居城市,但是我们必须返回城市 3,因为它的编号最大。
示例 2:

输入:n = 5, edges = [[0,1,2],[0,4,8],[1,2,3],[1,4,2],[2,3,1],[3,4,1]], distanceThreshold = 2
输出:0
解释:城市分布图如上。 
每个城市阈值距离 distanceThreshold = 2 内的邻居城市分别是:
城市 0 -> [城市 1] 
城市 1 -> [城市 0, 城市 4] 
城市 2 -> [城市 3, 城市 4] 
城市 3 -> [城市 2, 城市 4]
城市 4 -> [城市 1, 城市 2, 城市 3] 
城市 0 在阈值距离 4 以内只有 1 个邻居城市。
 

提示:

2 <= n <= 100
1 <= edges.length <= n * (n - 1) / 2
edges[i].length == 3
0 <= fromi < toi < n
1 <= weighti, distanceThreshold <= 10^4
所有 (fromi, toi) 都是不同的。

分析

这个题目考察什么内容同样是写在脸上的,核心就是要求图中任意两点间的最短距离,也就是考察最短路径Floyd算法,这也是最好写的最短路径算法,三重循环直接解决问题。

代码

class Solution {
    public int findTheCity(int n, int[][] edges, int distanceThreshold) {
        int[][] dis = new int[n][n];
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                dis[i][j] = 1000000;
            }
        }
        for(int i=0;i<edges.length;i++)
        {
            int start = edges[i][0];
            int end = edges[i][1];
            int weight = edges[i][2];
            dis[start][end] = weight;
            dis[end][start] = weight;
        }
        for(int i=0;i<n;++i)
        for(int j=0;j<n;++j)
        for(int k=0;k<n;++k)
            dis[j][k]=Math.min(dis[j][k],dis[j][i]+dis[i][k]);
        int res = -1;
        int minCount = 1000000;
        for(int i=0;i<n;i++)
        {
            int count = 0;
            for(int j=0;j<n;j++)
            {
                if(i!=j)
                {
                    if(dis[i][j]<=distanceThreshold)
                    {
                        count++;
                    }
                }
            }
            if(count<=minCount)
            {
                minCount = count;
                res = i;
                
            }
        }
        return res;
    }
}

5322. 工作计划的最低难度

题目描述

你需要制定一份 d 天的工作计划表。工作之间存在依赖,要想执行第 i 项工作,你必须完成全部 j 项工作( 0 <= j < i)。

你每天 至少 需要完成一项任务。工作计划的总难度是这 d 天每一天的难度之和,而一天的工作难度是当天应该完成工作的最大难度。

给你一个整数数组 jobDifficulty 和一个整数 d,分别代表工作难度和需要计划的天数。第 i 项工作的难度是 jobDifficulty[i]。

返回整个工作计划的 最小难度 。如果无法制定工作计划,则返回 -1 。

示例 1:

输入:jobDifficulty = [6,5,4,3,2,1], d = 2
输出:7
解释:第一天,您可以完成前 5 项工作,总难度 = 6.
第二天,您可以完成最后一项工作,总难度 = 1.
计划表的难度 = 6 + 1 = 7 
示例 2:

输入:jobDifficulty = [9,9,9], d = 4
输出:-1
解释:就算你每天完成一项工作,仍然有一天是空闲的,你无法制定一份能够满足既定工作时间的计划表。
示例 3:

输入:jobDifficulty = [1,1,1], d = 3
输出:3
解释:工作计划为每天一项工作,总难度为 3 。
示例 4:

输入:jobDifficulty = [7,1,7,1,7,1], d = 3
输出:15
示例 5:

输入:jobDifficulty = [11,111,22,222,33,333,44,444], d = 6
输出:843
 

提示:

1 <= jobDifficulty.length <= 300
0 <= jobDifficulty[i] <= 1000
1 <= d <= 10

分析

这个题目上午考试的时候没有做出来,下午看了前几名的代码才明白的,这个题目有点难度。首先,要读懂题目,题目告诉我们所有工作必须依次完成,每天的工作难度是这天完成的所有任务的最大难度,工作计划难度是每天难度的综合。之后,确定这一定是一个动态规划的题目,重点是找到状态转移方程。我们记dp[i][j]代表前i天完成j项工作的最小难度。那么下面最难的地方就是如何确定状态转移方程了。

我们再用max[i][j]记录第i项到第j项中所有工作任务的难度最大值。我们可以认为,把任务分i天完成,可以看作把这个工作数组切成i段。我们想要知道切成i段的最小代价可以转变为切成i-1段的最小代价加上切出第i段的代价。因此状态转移方程为

dp[i][j]=min(dp[i][j],dp[i−1][k]+max[k+1][j])(0≤k≤j−1)

代码

class Solution {
    public int minDifficulty(int[] jobDifficulty, int d) {
        int n = jobDifficulty.length;
        if(n<d) return -1;
        int[][] max = new int[n][n];
        for(int i=0;i<n;i++)
        {
            max[i][i] = jobDifficulty[i];
            for(int j=i+1;j<n;j++)
            {
                max[i][j] = Math.max(max[i][j-1],jobDifficulty[j]);
            }
        }
        int[][] dp = new int[d+1][n+1]; 
        for(int i=0;i<=d;i++)
        {
            for(int j=0;j<=n;j++)
            {
                dp[i][j] = 1000000;
            }
        }
        dp[0][0] = 0;
        for (int i = 1; i <= d; ++i){
            for (int j = i; j <= n - d + i; ++j){
                for (int k = i - 1; k < j; ++k)
                    dp[i][j] = Math.min(dp[i][j], dp[i - 1][k] + max[k][j - 1]);
            }
        }
        return dp[d][n];
    }
}
发布了85 篇原创文章 · 获赞 100 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/caozixuan98724/article/details/104087857
今日推荐