下面的题目是最近我在力扣上面刷了每日一题之后所做的总结。
题目一
比较字符串最小字母出现频次
定义一个函数 f(s)
,统计 s
中(按字典序比较)最小字母的出现频次 ,其中 s
是一个非空字符串。
例如,若 s = "dcce"
,那么 f(s) = 2
,因为字典序最小字母是 "c"
,它出现了 2 次。
现在,给你两个字符串数组待查表 queries
和词汇表 words
。对于每次查询 queries[i]
,需统计 words
中满足 f(queries[i])
< f(W)
的 词的数目 ,W
表示词汇表 words
中的每个词。
请你返回一个整数数组 answer
作为答案,其中每个 answer[i]
是第 i
次查询的结果。
示例 1:
输入:queries = ["cbd"], words = ["zaaaz"]
输出:[1]
解释:查询 f("cbd") = 1,而 f("zaaaz") = 3 所以 f("cbd") < f("zaaaz")。
示例 2:
输入:queries = ["bbb","cc"], words = ["a","aa","aaa","aaaa"]
输出:[1,2]
解释:第一个查询 f("bbb") < f("aaaa"),第二个查询 f("aaa") 和 f("aaaa") 都 > f("cc")。
这道题目主要难度在我看来是理解题意,如果不给你示例的话,是很难理解这道题目在干嘛的。而看了示例之后就很好理解了。首先你求出queries数组中每一个字符串最小字母出现的次数,然后和words中每一个字符串出现的最小字母次数比较,输出words中有多少字符串的最小字母出现的次数大于queries中的字符串。那么思路也就有了首先我们先完成一个函数函数的作用为计算一个字符串中最小字母出现的次数。
计算字符串中最小字母出现次数的函数:
int Get_des(char* arr) {
char smaller = 'z'; // 先设定最小的字符为 z
int i = 0;
int count = 0;
while (arr[i]) {
if (arr[i] < smaller) {
smaller = arr[i];
count = 1;
} else if (arr[i] == smaller) {
count++;
}
i++;
}
return count;
}
之后的思路也就是创建一个数组储存words数组中每一个字符串中最小字母的出现次数。再创建一个数组用于储存答案,这个答案数组的长度也很简单,queries中含有多少个字符串那么答案数组就有多大的长度。然后我们遍历queries数组为答案数组赋值
int* numSmallerByFrequency(char ** queries, int queriesSize, char ** words, int wordsSize, int* returnSize){
int* ret = (int*)malloc(sizeof(int)*queriesSize);//创建用于返回的答案数组
memset(ret,0,sizeof(int)*queriesSize);//将里面的值初始化为0
int wordscount[wordsSize];//这个数组用于储存words每一个字符串中最小字符出现的次数
for(int i = 0;i<wordsSize;i++)
{
wordscount[i] = get_des(words[i]);
//为wordscount数组赋值
}
for(int i = 0;i<queriesSize;i++)
{
int queriescount = get_des(queries[i]);//这个常量用于储存queries数组中每一个字符串
//最小字母出现的次数
for(int k = 0;k<wordsSize;k++)
{
if(wordscount[k]>queriescount)
ret[i]++;//如果words数组中出现了最小字母出现次数大于
//这个queries字符串中最小字母出现次数的情况
//那就让答案数组中的次数加1
}
}
*returnSize = queriesSize;
return ret;
}
做题链接:1170. 比较字符串最小字母出现频次 - 力扣(Leetcode)
题目二:
1171. 从链表中删去总和值为零的连续节点
给你一个链表的头节点 head
,请你编写代码,反复删去链表中由 总和 值为 0
的连续节点组成的序列,直到不存在这样的序列为止。
删除完毕后,请你返回最终结果链表的头节点。
你可以返回任何满足题目要求的答案。
(注意,下面示例中的所有序列,都是对 ListNode
对象序列化的表示。)
示例1:
输入:head = [1,2,-3,3,1]
输出:[3,1]
提示:答案 [1,2,1] 也是正确的。
示例2:
输入:head = [1,2,3,-3,4]
输出:[1,2,4]
示例3:
输入:head = [1,2,3,-3,-2]
输出:[1]
这道题要怎么解决呢?最简单的做法也就是找到原链表中子链和为0的情况将这条子链删除即可,那么首先寻找子链,因为有可能会删除第一个节点,为了方便可以添加一个哨兵卫。
下面是代码实现:
struct ListNode* removeZeroSumSublists(struct ListNode* head){
struct ListNode* newhead = (struct ListNode*)malloc(sizeof(struct ListNode));
newhead->val = 0;
newhead->next = head;
struct ListNode* cur = newhead;//用于确定子链的头节点
int x = 0;
while(cur)
{
struct ListNode* p = cur->next;//遍历寻找子链
while(p)
{
x = x+p->val;
if(x == 0)
{
cur->next = p->next;//删除和为0的子链
}
p = p->next;//遍历完这一条子链
}
//进行到这里就判完一条子链了,去判断下一条子链
x = 0;//重新为下一条子链,初始化判断条件
cur = cur->next;
}
return newhead->next;
}
做题链接:1171. 从链表中删去总和值为零的连续节点 - 力扣(Leetcode)
题目三
2475. 数组中不等三元组的数目
给你一个下标从 0 开始的正整数数组 nums
。请你找出并统计满足下述条件的三元组 (i, j, k)
的数目:
0 <= i < j < k < nums.length
nums[i]
、nums[j]
和nums[k]
两两不同 。
- 换句话说:
nums[i] != nums[j]
、nums[i] != nums[k]
且nums[j] != nums[k]
。
返回满足上述条件三元组的数目。
示例1:
输入:nums = [4,4,2,4,3]
输出:3
解释:下面列出的三元组均满足题目条件:
- (0, 2, 4) 因为 4 != 2 != 3
- (1, 2, 4) 因为 4 != 2 != 3
- (2, 3, 4) 因为 2 != 4 != 3
共计 3 个三元组,返回 3 。
注意 (2, 0, 4) 不是有效的三元组,因为 2 > 0 。
示例2:
输入:nums = [1,1,1,1,1]
输出:0
解释:不存在满足条件的三元组,所以返回 0 。
对于这道题目因为力扣所给的数组大小很小,所以第一种方法也就是直接暴力遍历,三个循环寻找符合条配件的三元组
方法一
int unequalTriplets(int* nums, int numsSize)
{
int count = 0;
//方法一:三重循环暴力查找
for(int i = 0;i<numsSize;i++)//一重循环寻找第一个数
{
for(int j = i+1;j<numsSize;j++)//二重循环寻找第二个数
{
for(int k = j+1;k<numsSize;k++)//三重循环寻找第三个数
{
if(nums[i]!=nums[j]&&nums[j]!=nums[k]&&nums[i]!=nums[k])
{
count++;//符合条件让计数器加1
}
}
}
}
return count;//返回计数器值
}
思路二:可以寻找三个不同的元素数量,让数量相乘,那么就能得到这三个元素所能组成的所有三元组可能性,遍历数组找到所有的三元组数量
int compare(const void* p1,const void* p2)
{
return *(int*)p1 - *(int*)p2;
}
int unequalTriplets(int* nums, int numsSize){
qsort(nums,numsSize,sizeof(int),compare);//先将原数组排序完成
int count = 0;
for(int i = 0,j = 0;i<numsSize;i=j)//这里i的变化为什么是让i变成j,下面我会做出解释
{
while(j<numsSize&&nums[j] == nums[i])
{
j++;
}
count += i*(j-i)*(numsSize-j);
/*由题意可知,数组元素的相对顺序不影响结果,因此我们可以将数组
//从小到大进行排序。排序后,数组中的相同元素一定是相邻的。
//当我们以某一堆相同的数 [i,j)作为三元组的中间元素时,
//这堆相同的元素的左边元素数目为 i,右边元素数目为 n−j,
//那么符合条件的三元组数目为(i*(j-i)*(n-j)),这里的n也就是numsSize
}
return count;
}
做题链接:2475. 数组中不等三元组的数目 - 力扣(Leetcode)
题目四
1375. 二进制字符串前缀一致的次数
给你一个长度为 n
、下标从 1 开始的二进制字符串,所有位最开始都是 0
。我们会按步翻转该二进制字符串的所有位(即,将 0
变为 1
)。
给你一个下标从 1 开始的整数数组 flips
,其中 flips[i]
表示对应下标 i
的位将会在第 i
步翻转。
二进制字符串 前缀一致 需满足:在第 i
步之后,在 闭 区间 [1, i]
内的所有位都是 1 ,而其他位都是 0 。
返回二进制字符串在翻转过程中 前缀一致 的次数。
示例 1:
输入:flips = [3,2,4,1,5]
输出:2
解释:二进制字符串最开始是 "00000" 。
执行第 1 步:字符串变为 "00100" ,不属于前缀一致的情况。
执行第 2 步:字符串变为 "01100" ,不属于前缀一致的情况。
执行第 3 步:字符串变为 "01110" ,不属于前缀一致的情况。
执行第 4 步:字符串变为 "11110" ,属于前缀一致的情况。
执行第 5 步:字符串变为 "11111" ,属于前缀一致的情况。
在翻转过程中,前缀一致的次数为 2 ,所以返回 2 。
示例 2:
输入:flips = [4,1,2,3]
输出:1
解释:二进制字符串最开始是 "0000" 。
执行第 1 步:字符串变为 "0001" ,不属于前缀一致的情况。
执行第 2 步:字符串变为 "1001" ,不属于前缀一致的情况。
执行第 3 步:字符串变为 "1101" ,不属于前缀一致的情况。
执行第 4 步:字符串变为 "1111" ,属于前缀一致的情况。
在翻转过程中,前缀一致的次数为 1 ,所以返回 1 。
这道题也就是给了你一个足够大的字符串(全0),然后给了你一个数组,数组里面的数字代表接下来字符串中的哪一个数字会从0变成1,然后题目要求你返回在翻转过程中有多少次前面数字全是1,后面数字全是0的情况。
这道题要求在经历第i次翻转之后,字符串中第1到i卫的数字都为1,这其实也就等价于前i次翻转中下标的最大值也就是i。
我先将代码写出来,之后举一个例子
int numTimesAllBlue(int* flips, int flipsSize)
{
int count = 0;//用于计算次数
int right = 0;//用以记录现在已经出现的最大下标为多少
for(int i = 0;i<flipsSize;i++)
{
right = fmax(right,flips[i]);//这里的fmax是一个比较大小函数,但这个函数最后返回的其实一个浮点数
//这里强制转化为int,在某些情况会出现数值错误
if(right == i+1)
{
count++;//这里也就是出现了前缀一致的情况了
}
}
return count;
}
举一个例子最容易理解:
做题链接:1375. 二进制字符串前缀一致的次数 - 力扣(Leetcode)
我现在还只是一个还在成长的小小萌新,如果有错误请各位大佬见谅。