第四篇刷题笔记
第一天
分糖果
分糖果 IIhttps://leetcode.cn/problems/distribute-candies-to-people/
排排坐,分糖果。
我们买了一些糖果
candies
,打算把它们分给排好队的n = num_people
个小朋友。给第一个小朋友 1 颗糖果,第二个小朋友 2 颗,依此类推,直到给最后一个小朋友
n
颗糖果。然后,我们再回到队伍的起点,给第一个小朋友
n + 1
颗糖果,第二个小朋友n + 2
颗,依此类推,直到给最后一个小朋友2 * n
颗糖果。重复上述过程(每次都比上一次多给出一颗糖果,当到达队伍终点后再次从队伍起点开始),直到我们分完所有的糖果。注意,就算我们手中的剩下糖果数不够(不比前一次发出的糖果多),这些糖果也会全部发给当前的小朋友。
返回一个长度为
num_people
、元素之和为candies
的数组,以表示糖果的最终分发情况(即ans[i]
表示第i
个小朋友分到的糖果数)。
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* distributeCandies(int candies, int num_people, int* returnSize) {
int* ans = malloc(sizeof(int) * num_people);
*returnSize = num_people;
memset(ans,0,sizeof(int) * num_people);
int v = 0;
while(candies){
int i = v + 1;
if(candies >= i){
ans[v % num_people] += i;
candies -= i;
}else{
ans[v % num_people] += candies;
candies = 0;
}
v ++;
}
return ans;
}
三角形的最大周长
三角形的最大周长https://leetcode.cn/problems/largest-perimeter-triangle/
给定由一些正数(代表长度)组成的数组
nums
,返回 由其中三个长度组成的、面积不为零的三角形的最大周长 。如果不能形成任何面积不为零的三角形,返回0
。
#include <stdlib.h>
// 比较函数,用于降序排序
int comp(const void* a, const void* b) {
return *(int*)b - *(int*)a;
}
// 计算能构成三角形的最大周长
int largestPerimeter(int* nums, int numsSize) {
// 如果数组元素少于 3 个,无法构成三角形,返回 0
if (numsSize < 3) {
return 0;
}
// 对数组进行降序排序
qsort(nums, numsSize, sizeof(int), comp);
// 遍历数组,从最大的三条边开始尝试
for (int i = 0; i < numsSize - 2; i++) {
// 判断当前三条边是否能构成三角形
if (nums[i + 1] + nums[i + 2] > nums[i]) {
// 如果能构成三角形,返回周长
return nums[i] + nums[i + 1] + nums[i + 2];
}
}
// 没有找到能构成三角形的三条边,返回 0
return 0;
}
找出满足差值条件的下标
找出满足差值条件的下标 Ihttps://leetcode.cn/problems/find-indices-with-index-and-value-difference-i/
给你一个下标从 0 开始、长度为
n
的整数数组nums
,以及整数indexDifference
和整数valueDifference
。你的任务是从范围
[0, n - 1]
内找出 2 个满足下述所有条件的下标i
和j
:
abs(i - j) >= indexDifference
且abs(nums[i] - nums[j]) >= valueDifference
返回整数数组
answer
。如果存在满足题目要求的两个下标,则answer = [i, j]
;否则,answer = [-1, -1]
。如果存在多组可供选择的下标对,只需要返回其中任意一组即可。注意:
i
和j
可能 相等 。
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* findIndices(int* nums, int numsSize, int indexDifference, int valueDifference, int* returnSize) {
int* ans = (int*)malloc(sizeof(int) * 2);
*returnSize = 2;
ans[0] = -1;
ans[1] = -1;
for(int i = 0;i < numsSize - indexDifference;i++){
for(int j = i + indexDifference;j < numsSize;j++){
if(abs(nums[i] - nums[j]) >= valueDifference){
ans[0] = i;
ans[1] = j;
break;
}
}
}
return ans;
}
第二天
重新排列数组
重新排列数组https://leetcode.cn/problems/shuffle-the-array/
给你一个数组
nums
,数组中有2n
个元素,按[x1,x2,...,xn,y1,y2,...,yn]
的格式排列。请你将数组按
[x1,y1,x2,y2,...,xn,yn]
格式重新排列,返回重排后的数组。
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* shuffle(int* nums, int numsSize, int n, int* returnSize) {
int* ans = (int*)malloc(sizeof(int)*2*n);
*returnSize = 2*n;
int left = 0;
int right = n;
int w = 0;
for(int i = 0;i <n;i++){
ans[w++] = nums[left++];
ans[w++] = nums[right++];
}
return ans;
}
判断是否可以赢得数字游戏
判断是否可以赢得数字游戏https://leetcode.cn/problems/find-if-digit-game-can-be-won/
给你一个 正整数 数组
nums
。Alice 和 Bob 正在玩游戏。在游戏中,Alice 可以从
nums
中选择所有个位数 或 所有两位数,剩余的数字归 Bob 所有。如果 Alice 所选数字之和 严格大于 Bob 的数字之和,则 Alice 获胜。如果 Alice 能赢得这场游戏,返回
true
;否则,返回false
。
#include <stdio.h>
#include <stdbool.h>
bool canAliceWin(int* nums, int numsSize) {
int sumSingle = 0, sumDouble = 0, sumOther = 0;
for (int i = 0; i < numsSize; i++) {
if (nums[i] >= 1 && nums[i] <= 9) {
sumSingle += nums[i];
} else if (nums[i] >= 10 && nums[i] <= 99) {
sumDouble += nums[i];
} else {
sumOther += nums[i];
}
}
return (sumSingle > sumOther + sumDouble) || (sumDouble > sumOther + sumSingle);
}
最低票价
最低票价https://leetcode.cn/problems/minimum-cost-for-tickets/
在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行。在接下来的一年里,你要旅行的日子将以一个名为
days
的数组给出。每一项是一个从1
到365
的整数。火车票有 三种不同的销售方式 :
- 一张 为期一天 的通行证售价为
costs[0]
美元;- 一张 为期七天 的通行证售价为
costs[1]
美元;- 一张 为期三十天 的通行证售价为
costs[2]
美元。通行证允许数天无限制的旅行。 例如,如果我们在第
2
天获得一张 为期 7 天 的通行证,那么我们可以连着旅行 7 天:第2
天、第3
天、第4
天、第5
天、第6
天、第7
天和第8
天。返回 你想要完成在给定的列表
days
中列出的每一天的旅行所需要的最低消费 。
int min(int a, int b) {
return a < b ? a : b;
}
int mincostTickets(int* days, int daysSize, int* costs, int costsSize) {
// 标记旅行的天数
int isTravelDay[366] = {0};
for (int i = 0; i < daysSize; i++) {
isTravelDay[days[i]] = 1;
}
// 定义动态规划数组
int dp[366];
memset(dp, 0, sizeof(dp));
// 动态规划过程
for (int i = 1; i <= 365; i++) {
if (!isTravelDay[i]) {
// 当天不旅行,花费和前一天相同
dp[i] = dp[i - 1];
} else {
// 当天旅行,计算三种选择的最小花费
dp[i] = min(dp[i - 1] + costs[0], min(dp[((i - 7) > 0)? (i - 7) : 0] + costs[1], dp[((i - 30) > 0)? (i - 30) : 0] + costs[2]));
}
}
return dp[days[daysSize - 1]];
}
第三天
破坏回文串
破坏回文串https://leetcode.cn/problems/break-a-palindrome/
给你一个由小写英文字母组成的回文字符串
palindrome
,请你将其中 一个 字符用任意小写英文字母替换,使得结果字符串的 字典序最小 ,且 不是 回文串。请你返回结果字符串。如果无法做到,则返回一个 空串 。
如果两个字符串长度相同,那么字符串
a
字典序比字符串b
小可以这样定义:在a
和b
出现不同的第一个位置上,字符串a
中的字符严格小于b
中的对应字符。例如,"abcc”
字典序比"abcd"
小,因为不同的第一个位置是在第四个字符,显然'c'
比'd'
小。
char* breakPalindrome(char* palindrome) {
int len = strlen(palindrome);
// 如果字符串长度为 1,无法破坏回文性质,返回空串
if (len == 1) {
return "";
}
// 遍历前半部分字符串
for (int i = 0; i < len / 2; i++) {
if (palindrome[i] != 'a') {
// 将不是 'a' 的字符替换为 'a'
palindrome[i] = 'a';
return palindrome;
}
}
// 如果前半部分都是 'a',将最后一个字符替换为 'b'
palindrome[len - 1] = 'b';
return palindrome;
}
统计X和Y频数相同的子矩阵数量
统计 X 和 Y 频数相等的子矩阵数量https://leetcode.cn/problems/count-submatrices-with-equal-frequency-of-x-and-y/
给你一个二维字符矩阵
grid
,其中grid[i][j]
可能是'X'
、'Y'
或'.'
,返回满足以下条件的子矩阵数量:
- 包含
grid[0][0]
'X'
和'Y'
的频数相等。- 至少包含一个
'X'
。
#include <stdio.h>
int numberOfSubmatrices(char** grid, int gridSize, int* gridColSize) {
int ans = 0;
// 计算前缀和
int xPrefix[gridSize + 1][gridColSize[0] + 1];
int yPrefix[gridSize + 1][gridColSize[0] + 1];
// 初始化前缀和数组
for (int i = 0; i <= gridSize; i++) {
for (int j = 0; j <= gridColSize[0]; j++) {
xPrefix[i][j] = 0;
yPrefix[i][j] = 0;
}
}
// 计算前缀和
for (int i = 1; i <= gridSize; i++) {
for (int j = 1; j <= gridColSize[0]; j++) {
xPrefix[i][j] = xPrefix[i - 1][j] + xPrefix[i][j - 1] - xPrefix[i - 1][j - 1];
yPrefix[i][j] = yPrefix[i - 1][j] + yPrefix[i][j - 1] - yPrefix[i - 1][j - 1];
if (grid[i - 1][j - 1] == 'X') {
xPrefix[i][j]++;
} else if (grid[i - 1][j - 1] == 'Y') {
yPrefix[i][j]++;
}
}
}
// 枚举所有以 (0, 0) 为左上角的子矩阵
for (int i = 1; i <= gridSize; i++) {
for (int j = 1; j <= gridColSize[0]; j++) {
int xCount = xPrefix[i][j];
int yCount = yPrefix[i][j];
// 判断是否满足条件
if (xCount == yCount && xCount > 0) {
ans++;
}
}
}
return ans;
}
合并排序的数组
合并排序的数组https://leetcode.cn/problems/sorted-merge-lcci/
给定两个排序后的数组 A 和 B,其中 A 的末端有足够的缓冲空间容纳 B。 编写一个方法,将 B 合并入 A 并排序。
初始化 A 和 B 的元素数量分别为 m 和 n。
void merge(int* A, int ASize, int m, int* B, int BSize, int n) {
int i = m - 1; // 指向数组 A 的最后一个有效元素
int j = n - 1; // 指向数组 B 的最后一个元素
int k = m + n - 1; // 指向合并后数组 A 的最后一个位置
// 从后往前比较 A 和 B 中的元素,将较大的元素放到 A 的末尾
while (i >= 0 && j >= 0) {
if (A[i] > B[j]) {
A[k] = A[i];
i--;
} else {
A[k] = B[j];
j--;
}
k--;
}
// 如果 B 中还有剩余元素,将其复制到 A 的前面
while (j >= 0) {
A[k] = B[j];
j--;
k--;
}
}
第四天
所有子字符串美丽值之和
所有子字符串美丽值之和https://leetcode.cn/problems/sum-of-beauty-of-all-substrings/
一个字符串的 美丽值 定义为:出现频率最高字符与出现频率最低字符的出现次数之差。
- 比方说,
"abaacc"
的美丽值为3 - 1 = 2
。给你一个字符串
s
,请你返回它所有子字符串的 美丽值 之和。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int beautySum(char* s) {
int number = 0;
int length = strlen(s);
int* arr = (int*)malloc(sizeof(int) * 26);
for (int i = 0; i < length; i++) {
// 每次外层循环开始时,将 arr 数组重新初始化为 0
memset(arr, 0, sizeof(int) * 26);
for (int j = i; j < length; j++) {
// 统计当前字符出现的次数
arr[s[j] - 'a']++;
int max = 0;
int min = 10000;
for (int k = 0; k < 26; k++) {
if (arr[k] > 0) {
if (arr[k] > max) {
max = arr[k];
}
if (arr[k] < min) {
min = arr[k];
}
}
}
// 计算当前子字符串的美丽值并累加到总和中
number += (max - min);
}
}
// 释放动态分配的内存
free(arr);
return number;
}
平方数之和
平方数之和https://leetcode.cn/problems/sum-of-square-numbers/
给定一个非负整数
c
,你要判断是否存在两个整数a
和b
,使得a2 + b2 = c
。
bool judgeSquareSum(int c) {
int left = 0;
int right = sqrt(c);
while(left <= right){
long long num = (long long)left * left + (long long)right * right;
if(num == c){
return true;
}else if(num < c){
left ++;
}else{
right --;
}
}
return false;
}
活字印刷
你有一套活字字模
tiles
,其中每个字模上都刻有一个字母tiles[i]
。返回你可以印出的非空字母序列的数目。注意:本题中,每个活字字模只能使用一次。
#include <stdio.h>
#include <string.h>
// 回溯函数,用于生成所有可能的排列组合
void backtrack(int* count, int* freq) {
for (int i = 0; i < 26; i++) {
if (freq[i] > 0) {
// 使用当前字符
freq[i]--;
// 增加结果计数器
(*count)++;
// 递归生成剩余字符的排列
backtrack(count, freq);
// 回溯,恢复当前字符的使用状态
freq[i]++;
}
}
}
int numTilePossibilities(char* tiles) {
int length = strlen(tiles);
if (length == 1) {
return 1;
}
// 用于存储每个字母的出现次数
int freq[26] = {0};
// 统计每个字母的出现次数
for (int i = 0; i < length; i++) {
freq[tiles[i] - 'A']++;
}
int ans = 0;
// 调用回溯函数
backtrack(&ans, freq);
return ans;
}
第五天
有效时间的数目
有效时间的数目https://leetcode.cn/problems/number-of-valid-clock-times/
给你一个长度为
5
的字符串time
,表示一个电子时钟当前的时间,格式为"hh:mm"
。最早 可能的时间是"00:00"
,最晚 可能的时间是"23:59"
。在字符串
time
中,被字符?
替换掉的数位是 未知的 ,被替换的数字可能是0
到9
中的任何一个。请你返回一个整数
answer
,将每一个?
都用0
到9
中一个数字替换后,可以得到的有效时间的数目。
#include <stdio.h>
#include <string.h>
int countTime(char* time) {
int hourWays = 1;
int minuteWays = 1;
// 处理小时部分
if (time[0] == '?' && time[1] == '?') {
hourWays = 24;
} else if (time[0] == '?') {
if (time[1] - '0' < 4) {
hourWays = 3;
} else {
hourWays = 2;
}
} else if (time[1] == '?') {
if (time[0] == '2') {
hourWays = 4;
} else {
hourWays = 10;
}
}
// 处理分钟部分
if (time[3] == '?' && time[4] == '?') {
minuteWays = 60;
} else if (time[3] == '?') {
minuteWays = 6;
} else if (time[4] == '?') {
minuteWays = 10;
}
return hourWays * minuteWays;
}
数组中两元素的最大乘积
数组中两元素的最大乘积https://leetcode.cn/problems/maximum-product-of-two-elements-in-an-array/
给你一个整数数组
nums
,请你选择数组的两个不同下标i
和j
,使(nums[i]-1)*(nums[j]-1)
取得最大值。请你计算并返回该式的最大值。
int comp(const void* a,const void* b){
return *(int*)b -*(int*)a;
}
int maxProduct(int* nums, int numsSize) {
qsort(nums,numsSize,sizeof(int),comp);
return (nums[0] - 1)*(nums[1] - 1);
}
给小朋友分糖果
给小朋友们分糖果 Ihttps://leetcode.cn/problems/distribute-candies-among-children-i/
给你两个正整数
n
和limit
。请你将
n
颗糖果分给3
位小朋友,确保没有任何小朋友得到超过limit
颗糖果,请你返回满足此条件下的 总方案数 。
int distributeCandies(int n, int limit) {
int count = 0;
// 枚举第一个小朋友得到的糖果数
for (int i = 0; i <= (i < limit? i : limit); i++) {
// 枚举第二个小朋友得到的糖果数
for (int j = 0; j <= (n - i < limit? n - i : limit); j++) {
int k = n - i - j;
// 判断第三个小朋友得到的糖果数是否在合理范围内
if (k >= 0 && k <= limit) {
count++;
}
}
}
return count;
}
第六天
找到最接近0的数字
找到最接近 0 的数字https://leetcode.cn/problems/find-closest-number-to-zero/
给你一个长度为
n
的整数数组nums
,请你返回nums
中最 接近0
的数字。如果有多个答案,请你返回它们中的 最大值 。
int findClosestNumber(int* nums, int numsSize) {
int ans = 0;
for(int i = 1;i < numsSize;i ++){
if(abs(nums[i]) < abs(nums[ans])){
ans = i;
}else if(abs(nums[i]) == abs(nums[ans])){
if(nums[i] > nums[ans]){
ans = i;
}
}
}
return nums[ans];
}
分割数组
分割数组https://leetcode.cn/problems/split-the-array/
给你一个长度为 偶数 的整数数组
nums
。你需要将这个数组分割成nums1
和nums2
两部分,要求:
nums1.length == nums2.length == nums.length / 2
。nums1
应包含 互不相同 的元素。nums2
也应包含 互不相同 的元素。如果能够分割数组就返回
true
,否则返回false
。
bool isPossibleToSplit(int* nums, int numsSize) {
int arr[101];
memset(arr,0,sizeof(int)*101);
for(int i = 0;i < numsSize;i++){
int n = nums[i];
arr[n] ++;
if(arr[n] > 2){
return false;
}
}
return true;
}
求出数字答案
求出数字答案https://leetcode.cn/problems/find-the-key-of-the-numbers/
给你三个 正 整数
num1
,num2
和num3
。数字
num1
,num2
和num3
的数字答案key
是一个四位数,定义如下:
- 一开始,如果有数字 少于 四位数,给它补 前导 0 。
- 答案
key
的第i
个数位(1 <= i <= 4
)为num1
,num2
和num3
第i
个数位中的 最小 值。请你返回三个数字 没有 前导 0 的数字答案。
int generateKey(int num1, int num2, int num3) {
int digits1[4] = {0}, digits2[4] = {0}, digits3[4] = {0};
int resultDigits[4];
// 将 num1 分解为四位数的每一位
for (int i = 3; i >= 0; i--) {
digits1[i] = num1 % 10;
num1 /= 10;
}
// 将 num2 分解为四位数的每一位
for (int i = 3; i >= 0; i--) {
digits2[i] = num2 % 10;
num2 /= 10;
}
// 将 num3 分解为四位数的每一位
for (int i = 3; i >= 0; i--) {
digits3[i] = num3 % 10;
num3 /= 10;
}
// 找出每一位上的最小值
for (int i = 0; i < 4; i++) {
resultDigits[i] = (digits1[i] < digits2[i])? digits1[i] : digits2[i];
resultDigits[i] = (resultDigits[i] < digits3[i])? resultDigits[i] : digits3[i];
}
// 组合结果
int result = 0;
for (int i = 0; i < 4; i++) {
result = result * 10 + resultDigits[i];
}
return result;
}
第七天
每一个查询的最大美丽值
每一个查询的最大美丽值https://leetcode.cn/problems/most-beautiful-item-for-each-query/
给你一个二维整数数组
items
,其中items[i] = [pricei, beautyi]
分别表示每一个物品的 价格 和 美丽值 。同时给你一个下标从 0 开始的整数数组
queries
。对于每个查询queries[j]
,你想求出价格小于等于queries[j]
的物品中,最大的美丽值 是多少。如果不存在符合条件的物品,那么查询的结果为0
。请你返回一个长度与
queries
相同的数组answer
,其中answer[j]
是第j
个查询的答案。
暴力破解(未通过)
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* maximumBeauty(int** items, int itemsSize, int* itemsColSize, int* queries, int queriesSize, int* returnSize) {
int* ans = (int*)malloc(sizeof(int)*queriesSize);
*returnSize = queriesSize;
for(int i = 0;i < queriesSize;i ++){
int n = queries[i];
int max_beauty = 0;
for(int j = 0 ;j < itemsSize;j ++){
if(items[j][0] > n){continue;}
if(items[j][0] <= n && items[j][1] > max_beauty){
max_beauty = items[j][1];
}
}
ans[i] = max_beauty;
}
return ans;
}
优化解(排序+二分查找)
int compare(const void *a, const void *b) {
return (*(int**)a)[0] - (*(int**)b)[0];
}
int query(int **items, int itemsSize, int q) {
int l = 0, r = itemsSize;
while (l < r) {
int mid = l + (r - l) / 2;
if (items[mid][0] > q) {
r = mid;
} else {
l = mid + 1;
}
}
if (l == 0) {
// 此时所有物品价格均大于查询价格
return 0;
} else {
// 返回小于等于查询价格的物品的最大美丽值
return items[l - 1][1];
}
}
int* maximumBeauty(int** items, int itemsSize, int* itemsColSize, int* queries, int queriesSize, int* returnSize) {
// 将物品按价格升序排序
qsort(items, itemsSize, sizeof(items[0]), compare);
// 按定义修改美丽值
for (int i = 1; i < itemsSize; ++i) {
if (items[i][1] < items[i-1][1]) {
items[i][1] = items[i-1][1];
}
}
// 二分查找处理查询
int* res = (int*)malloc(queriesSize * sizeof(int));
for (int i = 0; i < queriesSize; i++) {
res[i] = query(items, itemsSize, queries[i]);
}
*returnSize = queriesSize;
return res;
}
你可以获得的最大的硬币数目
你可以获得的最大的硬币数目https://leetcode.cn/problems/maximum-number-of-coins-you-can-get/
有 3n 堆数目不一的硬币,你和你的朋友们打算按以下方式分硬币:
- 每一轮中,你将会选出 任意 3 堆硬币(不一定连续)。
- Alice 将会取走硬币数量最多的那一堆。
- 你将会取走硬币数量第二多的那一堆。
- Bob 将会取走最后一堆。
- 重复这个过程,直到没有更多硬币。
给你一个整数数组
piles
,其中piles[i]
是第i
堆中硬币的数目。返回你可以获得的最大硬币数目。
int comp(const void* a,const void* b){
return *(int*)b - *(int*)a;
}
int maxCoins(int* piles, int pilesSize) {
qsort(piles,pilesSize,sizeof(int),comp);
int ans = 0;
int length = (pilesSize*2)/3;
for(int i = 0;i < length;i++){
if(i % 2 == 1){
ans += piles[i];
}
}
return ans;
}
有序数组中的单一元素
有序数组中的单一元素https://leetcode.cn/problems/single-element-in-a-sorted-array/
给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
请你找出并返回只出现一次的那个数。
你设计的解决方案必须满足
O(log n)
时间复杂度和O(1)
空间复杂度。
int singleNonDuplicate(int* nums, int numsSize) {
int ans = 0;
for(int i = 0;i < numsSize;i++){
ans = ans ^ nums[i];
}
return ans;
}
总结
第四周结束了 这周的效率不是很高 主要还是在写一些项目 精力比较分散 做的题也都比较简单 后面该做一做真题去练习