一、每日一题
提示
简单
1
相关企业
给你一个下标从 0 开始的字符串数组
words
,其中words[i]
要么是一个字符串形式的正整数,要么是字符串"prev"
。我们从数组的开头开始遍历,对于
words
中的每个"prev"
字符串,找到words
中的 上一个遍历的整数 ,定义如下:
k
表示到当前位置为止的连续"prev"
字符串数目(包含当前字符串),令下标从 0 开始的 整数 数组nums
表示目前为止遍历过的所有整数,同时用nums_reverse
表示nums
反转得到的数组,那么当前"prev"
对应的 上一个遍历的整数 是nums_reverse
数组中下标为(k - 1)
的整数。- 如果
k
比目前为止遍历过的整数数目 更多 ,那么上一个遍历的整数为-1
。请你返回一个整数数组,包含所有上一个遍历的整数。
示例 1:
输入:words
= ["1","2","prev","prev","prev"] 输出:[2,1,-1] 解释: 对于下标为 2 处的 "prev" ,上一个遍历的整数是 2 ,因为连续 "prev" 数目为 1 ,同时在数组 reverse_nums 中,第一个元素是 2 。 对于下标为 3 处的 "prev" ,上一个遍历的整数是 1 ,因为连续 "prev" 数目为 2 ,同时在数组 reverse_nums 中,第二个元素是 1 。 对于下标为 4 处的 "prev" ,上一个遍历的整数是 -1 ,因为连续 "prev" 数目为 3 ,但总共只遍历过 2 个整数。示例 2:
输入:words
= ["1","prev","2","prev","prev"] 输出:[1,2,1] 解释: 对于下标为 1 处的 "prev" ,上一个遍历的整数是 1 。 对于下标为 3 处的 "prev" ,上一个遍历的整数是 2 。 对于下标为 4 处的 "prev" ,上一个遍历的整数是 1 ,因为连续 "prev" 数目为 2 ,同时在数组 reverse_nums 中,第二个元素是 1 。提示:
1 <= words.length <= 100
words[i] == "prev"
或1 <= int(words[i]) <= 100
思路:
- 当处理"prev"时,需要考虑"prev"的连续出现。如果多个"prev"连续出现,需要依次处理它们,找到不为-1的整数作为上一个遍历的整数。
- 在遍历过程中,需要根据"k"和已经遍历的整数数量来确定上一个整数。如果"k"大于已经遍历的整数数量,上一个整数就是-1。
class Solution {
public List<Integer> lastVisitedIntegers(List<String> words) {
List<Integer> num=new ArrayList<>();
List<Integer> fx=new ArrayList<>();
int len=0;
for(String str:words) {
if(str.charAt(0)!='p') {
num.add(Integer.parseInt(str));
len=0;
}
else{
len++;
if(len>num.size())
{
fx.add(-1);
}
else fx.add(num.get(num.size()-len));
}
}
return fx;
}
}
提示
中等
3
相关企业
给你一个整数
n
和一个下标从 0 开始的字符串数组words
,和一个下标从 0 开始的 二进制 数组groups
,两个数组长度都是n
。你需要从下标
[0, 1, ..., n - 1]
中选出一个 最长子序列 ,将这个子序列记作长度为k
的[i0, i1, ..., ik - 1]
,对于所有满足0 < j + 1 < k
的j
都有groups[ij] != groups[ij + 1]
。请你返回一个字符串数组,它是下标子序列 依次 对应
words
数组中的字符串连接形成的字符串数组。如果有多个答案,返回任意一个。子序列 指的是从原数组中删掉一些(也可能一个也不删掉)元素,剩余元素不改变相对位置得到的新的数组。
注意:
words
中的字符串长度可能 不相等 。示例 1:
输入:n = 3, words = ["e","a","b"], groups = [0,0,1] 输出:["e","b"] 解释:一个可行的子序列是 [0,2] ,因为 groups[0] != groups[2] 。 所以一个可行的答案是 [words[0],words[2]] = ["e","b"] 。 另一个可行的子序列是 [1,2] ,因为 groups[1] != groups[2] 。 得到答案为 [words[1],words[2]] = ["a","b"] 。 这也是一个可行的答案。 符合题意的最长子序列的长度为 2 。示例 2:
输入:n = 4, words = ["a","b","c","d"], groups = [1,0,1,1] 输出:["a","b","c"] 解释:一个可行的子序列为 [0,1,2] 因为 groups[0] != groups[1] 且 groups[1] != groups[2] 。 所以一个可行的答案是 [words[0],words[1],words[2]] = ["a","b","c"] 。 另一个可行的子序列为 [0,1,3] 因为 groups[0] != groups[1] 且 groups[1] != groups[3] 。 得到答案为 [words[0],words[1],words[3]] = ["a","b","d"] 。 这也是一个可行的答案。 符合题意的最长子序列的长度为 3 。提示:
1 <= n == words.length == groups.length <= 100
1 <= words[i].length <= 10
0 <= groups[i] < 2
words
中的字符串 互不相同 。words[i]
只包含小写英文字母。
思路:
通过遍历一次
words
数组,检查相邻字符串的groups
值,找到最长满足条件的子序列,并将这些字符串存储在fn
列表中。如果i
是最后一个字符串(i == n - 1
),或者groups[i]
与下一个字符串的groups
值不相同(groups[i] != groups[i+1]
),这表示当前字符串是最长子序列的一部分。因为它与下一个字符串的groups
值不同,所以满足题目中的条件。
class Solution {
public List<String> getWordsInLongestSubsequence(int n, String[] words, int[] groups) {
List<String> fn=new ArrayList<>();
for(int i=0;i<words.length;i++)
{
if(i==n-1||groups[i]!=groups[i+1])
{
fn.add(words[i]);
}
}
return fn;
}
}
提示
困难
158
相关企业
我们有
n
栋楼,编号从0
到n - 1
。每栋楼有若干员工。由于现在是换楼的季节,部分员工想要换一栋楼居住。给你一个数组
requests
,其中requests[i] = [fromi, toi]
,表示一个员工请求从编号为fromi
的楼搬到编号为toi
的楼。一开始 所有楼都是满的,所以从请求列表中选出的若干个请求是可行的需要满足 每栋楼员工净变化为 0 。意思是每栋楼 离开 的员工数目 等于 该楼 搬入 的员工数数目。比方说
n = 3
且两个员工要离开楼0
,一个员工要离开楼1
,一个员工要离开楼2
,如果该请求列表可行,应该要有两个员工搬入楼0
,一个员工搬入楼1
,一个员工搬入楼2
。请你从原请求列表中选出若干个请求,使得它们是一个可行的请求列表,并返回所有可行列表中最大请求数目。
示例 1:
输入:n = 5, requests = [[0,1],[1,0],[0,1],[1,2],[2,0],[3,4]] 输出:5 解释:请求列表如下: 从楼 0 离开的员工为 x 和 y ,且他们都想要搬到楼 1 。 从楼 1 离开的员工为 a 和 b ,且他们分别想要搬到楼 2 和 0 。 从楼 2 离开的员工为 z ,且他想要搬到楼 0 。 从楼 3 离开的员工为 c ,且他想要搬到楼 4 。 没有员工从楼 4 离开。 我们可以让 x 和 b 交换他们的楼,以满足他们的请求。 我们可以让 y,a 和 z 三人在三栋楼间交换位置,满足他们的要求。 所以最多可以满足 5 个请求。示例 2:
输入:n = 3, requests = [[0,0],[1,2],[2,1]] 输出:3 解释:请求列表如下: 从楼 0 离开的员工为 x ,且他想要回到原来的楼 0 。 从楼 1 离开的员工为 y ,且他想要搬到楼 2 。 从楼 2 离开的员工为 z ,且他想要搬到楼 1 。 我们可以满足所有的请求。示例 3:
输入:n = 4, requests = [[0,3],[3,1],[1,2],[2,0]] 输出:4提示:
1 <= n <= 20
1 <= requests.length <= 16
requests[i].length == 2
0 <= fromi, toi < n
思路:
使用位运算和暴力搜索的方法,遍历了所有可能的请求分配方式,以找到能满足最多请求的方式。它通过不断更新
ans
来跟踪满足的请求数,同时使用flag
和fn
来模拟资源的分配情况。这是一个穷举的算法,复杂度相对较高,但能够找到正确答案。
class Solution {
public int maximumRequests(int n, int[][] requests) {
int ans=0;
int flag=0;
int len=requests.length;
for(int i=0;i<(1<<len);i++)
{
int k=count(i);
if(k<ans) continue;
flag=0;
int[ ] fn=new int[n];
for(int j=0;j<len;j++)
if(((i>>j)&1)==1)
{
if(++fn[requests[j][0]]==1) flag++;
if(--fn[requests[j][1]]==0) flag--;
}
if(flag==0) ans=k;
}
return ans;
}
int count(int x)
{
int sum=0;
for(int i=x;i>0;i-=(i&-i)) sum++;
return sum;
}
}
提示
中等
646
相关企业
给定一个长度为
n
的环形整数数组nums
,返回nums
的非空 子数组 的最大可能和 。环形数组 意味着数组的末端将会与开头相连呈环状。形式上,
nums[i]
的下一个元素是nums[(i + 1) % n]
,nums[i]
的前一个元素是nums[(i - 1 + n) % n]
。子数组 最多只能包含固定缓冲区
nums
中的每个元素一次。形式上,对于子数组nums[i], nums[i + 1], ..., nums[j]
,不存在i <= k1, k2 <= j
其中k1 % n == k2 % n
。示例 1:
输入:nums = [1,-2,3,-2] 输出:3 解释:从子数组 [3] 得到最大和 3示例 2:
输入:nums = [5,-3,5] 输出:10 解释:从子数组 [5,5] 得到最大和 5 + 5 = 10示例 3:
输入:nums = [3,-2,2,-3] 输出:3 解释:从子数组 [3] 和 [3,-2,2] 都可以得到最大和 3提示:
n == nums.length
1 <= n <= 3 * 104
-3 * 104 <= nums[i] <= 3 * 104
思路:
通过动态规划的方式计算了具有最大和的子数组,同时考虑了数组的循环特性。返回
max
和sum - min
中的较大值。这是因为要么具有最大和的子数组在数组中不环绕(max
),要么在数组中环绕(sum - min
),我们需要返回其中较大的那个。
class Solution {
public int maxSubarraySumCircular(int[] nums) {
int sum;
int[] maxnum=new int[nums.length];
int[] minnum=new int[nums.length];
int min=0,max=nums[0];
maxnum[0]=minnum[0]=nums[0];
sum=nums[0];
for(int i=1;i<nums.length;i++)
{
sum+=nums[i];
maxnum[i]=Math.max(maxnum[i-1]+nums[i],nums[i]);
if(max<maxnum[i]) max=maxnum[i];
}
for(int i=1;i<nums.length-1;i++)
{
minnum[i]=Math.min(minnum[i-1]+nums[i],nums[i]);
min=Math.min(min,minnum[i]);
}
return Math.max(max,sum-min);
}
}
提示
中等
39
相关企业
给你一个由正整数组成的数组
nums
和一个 正 整数k
。如果
nums
的子集中,任意两个整数的绝对差均不等于k
,则认为该子数组是一个 美丽 子集。返回数组
nums
中 非空 且 美丽 的子集数目。
nums
的子集定义为:可以经由nums
删除某些元素(也可能不删除)得到的一个数组。只有在删除元素时选择的索引不同的情况下,两个子集才会被视作是不同的子集。示例 1:
输入:nums = [2,4,6], k = 2 输出:4 解释:数组 nums 中的美丽子集有:[2], [4], [6], [2, 6] 。 可以证明数组 [2,4,6] 中只存在 4 个美丽子集。示例 2:
输入:nums = [1], k = 1 输出:1 解释:数组 nums 中的美丽数组有:[1] 。 可以证明数组 [1] 中只存在 1 个美丽子集。提示:
1 <= nums.length <= 20
1 <= nums[i], k <= 1000
思路:
使用递归的方式,对数组元素进行选择和排列,同时使用数组
b
来记录已选择的元素,以便找到美丽子集的数量。递归的基本思路是考虑当前元素是否包含在子集中,然后继续向下递归寻找下一个元素,同时需要注意存储已选择元素的记录和恢复。最后,返回美丽子集的数量。
class Solution {
int ans=-1;
public void fun(int[] a,int[] b,int n,int k)
{
int len=0;
if(n==a.length) {
ans++;
return ;}
fun(a,b,n+1,k);
len=a[n]+k;
if(b[len-k]==0&&b[len+k]==0)
{
++b[len];
fun(a,b,n+1,k);
--b[len];
}
}
public int beautifulSubsets(int[] nums, int k) {
Arrays.sort(nums);
int[] fn=new int[k*2+1010];
fun(nums,fn,0,k);
return ans;
}
}
提示
中等
738
相关企业
给你一个整数数组
nums
和一个整数k
,请你返回子数组内所有元素的乘积严格小于k
的连续子数组的数目。示例 1:
输入:nums = [10,5,2,6], k = 100 输出:8 解释:8 个乘积小于 100 的子数组分别为:[10]、[5]、[2],、[6]、[10,5]、[5,2]、[2,6]、[5,2,6]。 需要注意的是 [10,5,2] 并不是乘积小于 100 的子数组。示例 2:
输入:nums = [1,2,3], k = 0 输出:0提示:
1 <= nums.length <= 3 * 104
1 <= nums[i] <= 1000
0 <= k <= 106
思路:
使用双指针和滑动窗口的思想,通过动态计算乘积并根据乘积大小来调整窗口大小,找到符合条件的子数组数量。这个方法的优点在于时间复杂度较低,只需要一次遍历数组。
class Solution {
public int numSubarrayProductLessThanK(int[] nums, int k) {
int left=0,num=1,result=0;
for(int i=0;i<nums.length;i++)
{
num*=nums[i];
while(num>=k&&left<=i)
{
num/=nums[left++];
}
result+=i-left+1;
}
return result;
}
}