博客首页:崇尚学技术的科班人
小肖来了
今天给大家带来的文章是《LeetCode第277场周赛》
希望各位小伙伴们能够耐心的读完这篇文章
博主也在学习阶段,如若发现问题,请告知,非常感谢
同时也非常感谢各位小伙伴们的支持
Java
技术的热爱以及忙着框架的学习,也就没有输出算法之类的文章,但博主对算法也是爱的深沉也并没又落下对算法的学习。最近博主也报名参加了蓝桥杯的比赛,所以最近的算法力度可能会很大。同时,小伙伴们也不能落下对算法的学习哟。LeetCode
周赛算法题好水,前三题我十几分钟就 A
了。第四题从数据上看是暴力,但是判断该方案的是否合法的方式没有想清楚,看了y
总的讲解之后才明白。所以总体上来说这场周赛巩固的只有暴力了 /(ㄒoㄒ)/~~
。那我们就来讲讲这周周赛题目吧。元素计数
给你一个整数数组
nums
,统计并返回在nums
中同时具有一个严格较小元素和一个严格较大元素的元素数目。
示例1
:输入:nums = [11,7,2,15]
输出:2
解释:元素 7 :严格较小元素是元素 2 ,严格较大元素是元素 11 。
元素 11 :严格较小元素是元素 7 ,严格较大元素是元素 15 。
总计有 2 个元素都满足在 nums 中同时存在一个严格较小元素和一个严格较大元素。
示例2
:输入:nums = [-3,3,3,90]
输出:2
解释:元素 3 :严格较小元素是元素 -3 ,严格较大元素是元素 90 。
由于有两个元素的值为 3 ,总计有 2 个元素都满足在 nums 中同时存在一个严格较小元素和一个严格较大元素。
1 <= nums.length <= 100
-105 <= nums[i] <= 105
思路一
我先说说我的思路,因为它要求是求同时具有严格较小元素和严格较大元素的元素数目。我的思路是我们先求出最大值和最小值。如果最大值等于最小值的话,那么它一定不存在同时具有严格较小元素和严格较大元素的元素。然后我们对最大值和最小值的个数进行计数,那么最后的答案就是数组元素个数减去最大值和最小值的元素之和。
- 那么有小伙伴就会问那如果最大值和最小值不相等,但又不存在相应的所求元素时呢?
哈哈,其实数组元素个数减去最大值和最小值的元素之和已经包含了这种情况了,因为此时最大值和最小值的元素之和必然等于数组元素个数,所以也就是答案0
。
思路二
还有一种思路就是对数组元素排序,然后统计不是最大值和最小值的元素个数。其实这样的话时间开销会比思路一更大。
class Solution {
public int countElements(int[] num) {
int minv = Integer.MAX_VALUE, maxv = Integer.MIN_VALUE;
for(int i = 0; i < num.length; i ++){
if(num[i] < minv) minv = num[i];
if(num[i] > maxv) maxv = num[i];
}
if(minv == maxv) return 0;
int cnt1 = 0, cnt2 = 0;
for(int i = 0; i < num.length; i ++){
if(num[i] == minv) cnt1 ++;
if(num[i] == maxv) cnt2 ++;
}
return num.length - cnt1 - cnt2;
}
}
按符号重排数组
给你一个下标从
0
开始的整数数组nums
,数组长度为 偶数 ,由数目相等的正整数和负整数组成。
你需要 重排nums
中的元素,使修改后的数组满足下述条件:
- 任意 连续 的两个整数 符号相反
- 对于符号相同的所有整数,保留 它们在
nums
中的 顺序 。- 重排后数组以正整数开头。
重排元素满足上述条件后,返回修改后的数组。
示例1
:输入:nums = [3,1,-2,-5,2,-4]
输出:[3,-2,1,-5,2,-4]
解释:
nums 中的正整数是 [3,1,2] ,负整数是 [-2,-5,-4] 。
重排的唯一可行方案是 [3,-2,1,-5,2,-4],能满足所有条件。
像 [1,-2,2,-5,3,-4]、[3,1,2,-2,-5,-4]、[-2,3,-5,1,-4,2] 这样的其他方案是不正确的,因为不满足一个或者多个条件。
示例2
:输入:nums = [-1,1]
输出:[1,-1]
解释:
1 是 nums 中唯一一个正整数,-1 是 nums 中唯一一个负整数。
所以 nums 重排为 [1,-1] 。
-2 <= nums.length <= 2 * 105
nums.length
是 偶数1 <= |nums[i]| <= 105
nums
由 相等 数量的正整数和负整数组成思路
我的思路应该是简单明了,直接暴力求就OK
了,我先顺序遍历将正数和负数按数组中的顺序分别放入相应的集合。再创建一个数组将其按照题目中的要求下标为奇数时放入负数,下标为偶数时放入正数。
class Solution {
public int[] rearrangeArray(int[] nums) {
int[] num = new int[nums.length];
List<Integer> list = new ArrayList<>();
List<Integer> list1 = new ArrayList<>();
for(int i = 0; i < nums.length; i ++){
if(nums[i] < 0) list.add(nums[i]);
else list1.add(nums[i]);
}
int j = 0, k = 0;
for(int i = 0; i < num.length; i ++){
if(i % 2 == 0) num[i] = list1.get(j ++);
else num[i] = list.get(k ++);
}
return num;
}
}
找出数组中的所有孤独数字
给你一个整数数组
nums
。如果数字x
在数组中仅出现 一次 ,且没有 相邻 数字(即,x + 1
和x - 1
)出现在数组中,则认为数字x
是 孤独数字 。
返回nums
中的 所有 孤独数字。你可以按 任何顺序 返回答案
示例1
:输入:nums = [10,6,5,8]
输出:[10,8]
解释:
- 10 是一个孤独数字,因为它只出现一次,并且 9 和 11 没有在 nums 中出现。
- 8 是一个孤独数字,因为它只出现一次,并且 7 和 9 没有在 nums 中出现。
- 5 不是一个孤独数字,因为 6 出现在 nums 中,反之亦然。
因此,nums 中的孤独数字是 [10, 8] 。
注意,也可以返回 [8, 10] 。
示例2
:输入:nums = [1,3,5,3]
输出:[1,5]
解释:
- 1 是一个孤独数字,因为它只出现一次,并且 0 和 2 没有在 nums 中出现。
- 5 是一个孤独数字,因为它只出现一次,并且 4 和 6 没有在 nums 中出现。
- 3 不是一个孤独数字,因为它出现两次。
因此,nums 中的孤独数字是 [1, 5] 。
注意,也可以返回 [5, 1] 。
1 <= nums.length <= 105
0 <= nums[i] <= 106
思路
这里我们是先对各个数进行计数,然后正向遍历数组查看是否满足其在数组中只出现一次,且相邻数字未出现在数组中,如果满足就进行加一。
class Solution {
public List<Integer> findLonely(int[] nums) {
Map<Integer,Integer> map = new HashMap<>();
for(int i = 0;i < nums.length; i ++)
map.put(nums[i],map.getOrDefault(nums[i],0) + 1);
List<Integer> list = new ArrayList<>();
for(int i = 0; i < nums.length; i ++){
int cnt = map.get(nums[i]);
int cnt1 = map.getOrDefault(nums[i] - 1,0);
int cnt2 = map.getOrDefault(nums[i] + 1,0);
if(cnt == 1 && cnt1 == 0 && cnt2 == 0){
list.add(nums[i]);
}
}
return list;
}
}
基于陈述统计最多好人数
游戏中存在两种角色:
- 好人:该角色只说真话。
- 坏人:该角色可能说真话,也可能说假话。
给你一个下标从 0 开始的二维整数数组
statements
,大小为n x n
,表示n
个玩家对彼此角色的陈述。具体来说,statements[i][j]
可以是下述值之一:
0
表示i
的陈述认为j
是 坏人 。1
表示i
的陈述认为j
是 好人 。2
表示i
没有对j
作出陈述。另外,玩家不会对自己进行陈述。形式上,对所有
0 <= i < n
,都有statements[i][i] = 2
。
根据这n
个玩家的陈述,返回可以认为是 好人 的 最大 数目。
示例1
:- 1 认为 0 是好人。
- 2 认为 1 是坏人。
以 2 为突破点。
- 假设 2 是一个好人:
- 基于 2 的陈述,1 是坏人。
- 那么可以确认 1 是坏人,2 是好人。
- 基于 1 的陈述,由于 1 是坏人,那么他在陈述时可能:
- 说真话。在这种情况下会出现矛盾,所以假设无效。
- 说假话。在这种情况下,0 也是坏人并且在陈述时说假话。
- 在认为 2 是好人的情况下,这组玩家中只有一个好人。
- 假设 2 是一个坏人:
- 基于 2 的陈述,由于 2 是坏人,那么他在陈述时可能:
- 说真话。在这种情况下,0 和 1 都是坏人。
- 在认为 2 是坏人但说真话的情况下,这组玩家中没有一个好人。
- 说假话。在这种情况下,1 是好人。
- 由于 1 是好人,0 也是好人。
- 在认为 2 是坏人且说假话的情况下,这组玩家中有两个好人。
在最佳情况下,至多有两个好人,所以返回 2 。
注意,能得到此结论的方法不止一种。
示例2
:- 1 认为 0 是好人。
- 2 认为 1 是坏人。
以 2 为突破点。
- 假设 2 是一个好人:
- 基于 2 的陈述,1 是坏人。
- 那么可以确认 1 是坏人,2 是好人。
- 基于 1 的陈述,由于 1 是坏人,那么他在陈述时可能:
- 说真话。在这种情况下会出现矛盾,所以假设无效。
- 说假话。在这种情况下,0 也是坏人并且在陈述时说假话。
- 在认为 2 是好人的情况下,这组玩家中只有一个好人。
- 假设 2 是一个坏人:
- 基于 2 的陈述,由于 2 是坏人,那么他在陈述时可能:
- 说真话。在这种情况下,0 和 1 都是坏人。
- 在认为 2 是坏人但说真话的情况下,这组玩家中没有一个好人。
- 说假话。在这种情况下,1 是好人。
- 由于 1 是好人,0 也是好人。
- 在认为 2 是坏人且说假话的情况下,这组玩家中有两个好人。
在最佳情况下,至多有两个好人,所以返回 2 。
注意,能得到此结论的方法不止一种。
n == statements.length == statements[i].length
2 <= n <= 15
statements[i][j]
的值为 0
、1
或 2
statements[i][i] == 2
思路
这道题我也是看了y
总的讲解才会的,根据数据大小的话,显然可以进行暴力求解,且不会超时的。我们这里使用二进制表示进行枚举方案,因为一共最多也就15
人,根据好坏划分,那么也就是2 ^ 15
种方案,我们枚举方案取好人最多的合法方案。然后判断该方案是否合法。不合法的时候也就是当第j
个人是好人时,那么他说的一定是真话,而它所断言的对象却与他所说的不符那么该方案也就不合法了。我们就不要对该方案进行好人统计即可。
class Solution {
public int maximumGood(int[][] g) {
int n = g.length;
int res = 0;
for(int i = 0; i < 1 << n; i ++){
boolean flag = true;
for(int j = 0; j < n; j ++){
for(int k = 0; k < n; k ++){
if(g[j][k] != 2){
if(((i >> j) & 1) == 1){
if(((i >> k) & 1) != g[j][k]) flag = false;
}
}
}
}
if(flag == true){
int cnt = 0;
for(int j = 0; j < n; j ++){
if(((i >> j) & 1) == 1) cnt ++;
}
res = Math.max(res,cnt);
}
}
return res;
}
}