当前位置: 首页 > news >正文

C语言刷题日记 #6

C语言刷题日记 #7(2026.04.14-2026.04.21)

本周概览

进入四月的第三周,转专业申请的号角正式吹响了。4月15日至4月21日,于我个人而言是异常忙碌的一周——我咬着牙改完了个人陈述的第九版,提交了转专业申请表,也终于确定分流志愿是高分子。尽管日程紧凑,刷题这件事依然是雷打不动的。

本周的刷题内容很有特色,重点攻克了滑动窗口这个转专业机考的核心考点,同时也穿插了哈希表、股票问题、买卖最佳时机等经典题型。从4月中旬开始,我的算法练习进入了“查漏补缺+针对性强化”阶段,聚焦于那些在转专业机考中最高频的题型——滑动窗口和哈希表。

本周练习主要涉及:

  • 4月15日:1. 两数之和(哈希表)
  • 4月16日:2958. 最多 K 个重复元素的最长子数组(带频次控制的滑动窗口)
  • 4月17日:209. 长度最小的子数组 / 713. 乘积小于 K 的子数组 / 1004. 最大连续1的个数 III / 2024. 考试的最大困扰度 / 2904. 最短且字典序最小的美丽子字符串 / 3258. 统计满足 K 约束的子字符串数量 I / 3795. 不同元素和至少为 K 的最短子数组长度(滑动窗口大合集)
  • 4月18日:2441. 与对应负数同时存在的最大正整数(哈希集)
  • 4月19日:121. 买卖股票的最佳时机(一次扫描/动态规划)
  • 4月20日:2016. 增量元素之间的最大差值(一次扫描)
  • 4月21日:624. 数组列表中的最大距离 / 1128. 等价多米诺骨牌对的数量 / 1679. K 和数对的最大数目(哈希映射)

题目复盘

1. 1. 两数之和

我的代码:

int*twoSum(int*nums,intnumsSize,inttarget,int*returnSize){int*arr=(int*)malloc(sizeof(int)*3);inti,j;*returnSize=2;for(i=0;i<numsSize-1;i++){for(j=i+1;j<numsSize;j++){if(nums[i]+nums[j]==target){arr[0]=i;arr[1]=j;returnarr;}}}returnarr;}
  • 思路:暴力双循环枚举所有数对。

  • 不足之处:时间复杂度O ( n ) 2 O(n)^2O(n)2,对于数组长度很大时会超时;用三层数组大小申请但没有利用好内存;缺少注释说明。

  • 改进方向(哈希表法,O ( n ) O(n)O(n):遍历数组,对于每个数nums[i],判断target-nums[i]是否已在哈希表中:

typedefstruct{intkey;intval;}HashNode;// 复杂度更优,但直接调库实现哈希表需要依赖uthash,C语言调试略繁琐// 或者用数组法(nums元素范围有限时)int*twoSum(int*nums,intnumsSize,inttarget,int*returnSize){int*arr=(int*)malloc(2*sizeof(int));*returnSize=2;inthash[20001]={0};for(inti=0;i<numsSize;i++){intcomplement=target-nums[i];if(hash[complement+10000]!=0){arr[0]=hash[complement+10000]-1;arr[1]=i;returnarr;}hash[nums[i]+10000]=i+1;}returnarr;}

2. 121. 买卖股票的最佳时机

我的代码:

intmaxProfit(int*prices,intpricesSize){intret=0,minPrice=INT_MAX,right;for(right=0;right<pricesSize;right++){if(minPrice<prices[right])ret=fmax(ret,prices[right]-minPrice);minPrice=fmin(minPrice,prices[right]);}returnret;}
  • 思路:一次扫描,维护历史最低价格,计算当天价格与最低价的差价。

  • 不足之处:判断条件if(minPrice<prices[right])前后的顺序可以更清晰;变量right作为循环索引但并未体现“滑动窗口”含义。

  • 改进方向:交换顺序更好理解:

intmaxProfit(int*prices,intpricesSize){intminPrice=INT_MAX,maxProfit=0;for(inti=0;i<pricesSize;i++){minPrice=fmin(minPrice,prices[i]);maxProfit=fmax(maxProfit,prices[i]-minPrice);}returnmaxProfit;}

3. 209. 长度最小的子数组

我的代码:

intminSubArrayLen(inttarget,int*nums,intnumsSize){intleft,right,sum=0,min=INT_MAX;for(left=right=0;right<numsSize;){while(sum<target&&right<numsSize){sum+=nums[right];right++;}while(sum>=target){min=fmin(min,right-left);sum-=nums[left];left++;}}if(min==INT_MAX)return0;returnmin;}
  • 思路:双循环滑动窗口,先右扩直到满足条件,再左缩更新答案。

  • 不足之处:当窗口内多个连续数满足条件时,必须逐个左移指针,否则可能错过更短的窗口;滑动窗口对“正整数数组”有效,但若允许负数(本题不适用),窗口长度最小化会失效。

  • 改进方向:用while嵌套逻辑完整,但是写成标准模板更清晰:

intminSubArrayLen(inttarget,int*nums,intnumsSize){intleft=0,sum=0,minLen=INT_MAX;for(intright=0;right<numsSize;right++){sum+=nums[right];while(sum>=target){minLen=fmin(minLen,right-left+1);sum-=nums[left];left++;}}returnminLen==INT_MAX?0:minLen;}

4. 713. 乘积小于 K 的子数组

我的代码:

intnumSubarrayProductLessThanK(int*nums,intnumsSize,intk){if(k==0)return0;intleft,right;longlongplus=1,sum=0;for(left=right=0;right<numsSize;right++){plus*=nums[right];while(left<right&&plus>=k){plus/=nums[left];left++;}if(nums[right]<k){sum+=right-left+1;}}returnsum;}
  • 思路:滑动窗口,乘积小于k时计数当前窗口子数组数并累加。

  • 不足之处:引入了if(nums[right]<k)过滤冗余,但这会跳过窗口内包含nums[right]但大于等于k的乘积计算,可能导致漏计子数组;处理k==0的情况需要单独判断,可读性需提升。

  • 改进方向:统一滑动窗口,每次计数子数组时相加right-left+1

intnumSubarrayProductLessThanK(int*nums,intnumsSize,intk){if(k<=1)return0;longlongproduct=1;intleft=0,count=0;for(intright=0;right<numsSize;right++){product*=nums[right];while(product>=k)product/=nums[left++];count+=right-left+1;}returncount;}

5. 1004. 最大连续1的个数 III

我的代码:

intlongestOnes(int*nums,intnumsSize,intk){intleft,right,sum0=0,max=0;for(left=right=0;right<numsSize;right++){sum0+=nums[right]==0?1:0;max=fmax(max,right-left);while(sum0>k){sum0-=nums[left]==0?1:0;left++;}}returnfmax(max,right-left);}
  • 思路:滑动窗口,统计窗口内0的个数,当0的个数大于k时移动左指针收缩窗口。

  • 不足之处right-left先求值再收缩可能导致长度统计偏差;maxwhile之前更新可能记录过长窗口;最终返回值需要和前一个计算合并。

  • 改进方向:统一在右指针遍历过程中维护窗口内0的个数,保证窗口内0的个数始终≤k:

intlongestOnes(int*nums,intnumsSize,intk){intleft=0,maxLen=0,zeroCount=0;for(intright=0;right<numsSize;right++){if(nums[right]==0)zeroCount++;while(zeroCount>k){if(nums[left]==0)zeroCount--;left++;}maxLen=fmax(maxLen,right-left+1);}returnmaxLen;}

6. 2024. 考试的最大困扰度

我的代码:

intmaxConsecutiveAnswers(char*answerKey,intk){intsumF=0,sumT=0,max=0,left,right;for(left=0,right=0;right<strlen(answerKey);right++){if(answerKey[right]=='T')sumT++;elsesumF++;max=fmax(max,right-left);while(sumT>k){if(answerKey[left]=='T')sumT--;elsesumF--;left++;}}max=fmax(max,right-left);sumF=sumT=0;for(left=0,right=0;right<strlen(answerKey);right++){if(answerKey[right]=='T')sumT++;elsesumF++;max=fmax(max,right-left);while(sumF>k){if(answerKey[left]=='T')sumT--;elsesumF--;left++;}}returnfmax(max,right-left);}
  • 思路:两次滑动窗口,分别统计T和F,允许最多翻转k个。

  • 不足之处:代码重复(两次滑动窗口逻辑几乎一样),可重构为函数;多次调用strlen(answerKey)效率低;max更新逻辑不统一。

  • 改进方向:抽取maxConsecutiveChar函数处理单个字符:

intmaxConsecutiveChar(char*s,charch,intk){intleft=0,maxLen=0,count=0,n=strlen(s);for(intright=0;right<n;right++){if(s[right]!=ch)count++;while(count>k){if(s[left]!=ch)count--;left++;}maxLen=fmax(maxLen,right-left+1);}returnmaxLen;}intmaxConsecutiveAnswers(char*answerKey,intk){returnfmax(maxConsecutiveChar(answerKey,'T',k),maxConsecutiveChar(answerKey,'F',k));}

7. 2958. 最多 K 个重复元素的最长子数组

我的代码:

intmaxSubarrayLength(int*nums,intnumsSize,intk){inti,left,right,maxLength=0,max=INT_MIN,min=INT_MAX;int*hush=(int*)malloc(1000000001*sizeof(int));memset(hush,0,1000000001*sizeof(int));for(left=0,right=0;right<numsSize;++right){++hush[nums[right]];if(hush[nums[right]]>k){maxLength=fmax(right-left,maxLength);--hush[nums[left]];++left;for(;hush[nums[left-1]]<k;++left){--hush[nums[left]];}}}free(hush);returnfmax(right-left,maxLength);}
  • 思路:哈希表记录每个元素的出现次数,超过k时向左移动指针收缩窗口。

  • 不足之处:哈希表大小1000000001(10亿+1)过大,内存可能不足;移动指针的复杂循环逻辑容易出错;全局变量min/max未使用。

  • 改进方向:使用动态哈希数组(根据nums实际值范围分配),或用哈希表映射元素值与频次,简单通过while (hush[nums[right]] > k)收缩窗口:

intmaxSubarrayLength(int*nums,intnumsSize,intk){int*freq=(int*)calloc(100001,sizeof(int));intleft=0,maxLen=0;for(intright=0;right<numsSize;right++){freq[nums[right]]++;while(freq[nums[right]]>k){freq[nums[left]]--;left++;}maxLen=fmax(maxLen,right-left+1);}free(freq);returnmaxLen;}

8. 2016. 增量元素之间的最大差值

我的代码:

intmaximumDifference(int*nums,intnumsSize){intret=-1,minPrice=INT_MAX,right;for(right=0;right<numsSize;right++){if(minPrice<nums[right])ret=fmax(ret,nums[right]-minPrice);minPrice=fmin(minPrice,nums[right]);}returnret;}
  • 思路:一次扫描,维护最小值,求max(nums[i]-minPrice)。

  • 不足之处:几乎和股票问题121重复,但是条件要求j>i,要求差值至少为1而不是利润可为0。代码逻辑没问题但可以更聚焦于题目设定。

  • 改进方向:改if(minPrice<nums[right])if(minPrice <= nums[right])更符合严格递增需求,但题目不禁止相同值的交换:

intmaximumDifference(int*nums,intnumsSize){intminPrice=INT_MAX,maxDiff=-1;for(inti=0;i<numsSize;i++){if(nums[i]>minPrice){maxDiff=fmax(maxDiff,nums[i]-minPrice);}minPrice=fmin(minPrice,nums[i]);}returnmaxDiff;}

9. 2904. 最短且字典序最小的美丽子字符串

我的代码:(篇幅较长,略)

  • 思路:滑动窗口统计1的个数,当1的个数==k时,比较当前子串与已记录的最优子串,维护长度最短且字典序最小的字符串。

  • 不足之处:代码较长,使用多次malloc、strcmp和strcpy;动态处理字符串时的边界条件复杂,容易发生内存泄漏;len=INT_MAX的初始化取值可疑。

  • 改进方向:抽象出子串生成操作,用变量存储最短子串起始、结束位置,避免反复复制字符串:

char*shortestBeautifulSubstring(char*s,intk){intn=strlen(s);intbestStart=-1,bestLen=INT_MAX;intleft=0,ones=0;for(intright=0;right<n;right++){ones+=s[right]-'0';while(ones==k){intlen=right-left+1;if(len<bestLen){bestStart=left;bestLen=len;}elseif(len==bestLen&&strncmp(s+left,s+bestStart,len)<0){bestStart=left;}ones-=s[left]-'0';left++;}}if(bestStart==-1)return"";char*res=(char*)malloc((bestLen+1)*sizeof(char));strncpy(res,s+bestStart,bestLen);res[bestLen]='\0';returnres;}

本周总结

这一周我真正感受到滑动窗口这一算法并不是一个神秘的“黑盒子”,当熟记背后的逻辑后就变成了一种稳定的工具。滑动窗口的核心思想其实很简单:用两个指针维护一个窗口,通过条件来动态调整窗口的大小和位置,计算窗口内的性质并更新答案。今天能够用它的变体解决题目大多是“找满足条件的最长/最短连续数组”,我甚至开始对这类题目的模式有了肌肉记忆。

这一周提升的点主要有:

  • 从“只会暴力枚举”过渡到“先想滑动窗口”,理解了滑动窗口的优势——时间复杂度从O ( n ) 2 O(n)^2O(n)2降到O ( n ) O(n)O(n),空间复杂度一般O ( 1 ) O(1)O(1)
  • 开始用whileif组合处理窗口内计数和边界收缩,比之前复杂的嵌套结构简洁了更多;
  • 开始仔细考虑内存分配和变量作用域,确保C语言实现没有内存泄漏。

当然,改进的空间还有很多,尤其是字符串字典序处理和哈希表代替数组的写法,这些是我下个阶段要重点刷的题。但能一步步看着自己从写很复杂难懂的绕弯子代码,到今天对每个滑动窗口都能在脑海里快速搭建结构,终究是在往前走的。

这一周也完成了两件大事——成功提交了转专业申请表,也完成了分流志愿的填报。无论最后结果如何,我都为自己这半年多来的坚持感到骄傲。计算机学院的大门还在前方闪闪发光,我会一以贯之地顺着这个向往的方向走下去。

:本周所有代码已上传至我的GitHub仓库:LeetCode-C-Practice/2026-04-第三周

http://www.jsqmd.com/news/700868/

相关文章:

  • CentOS 7 安装与使用教程(手把手图文详解版)
  • 投稿踩坑3个月,被拒两次才发现:一开始的选刊方向就错了
  • 阿里云AgentBay SDK:云端沙盒环境为AI智能体提供安全执行能力
  • 如何用PyMICAPS快速制作专业气象图表:从数据到可视化的一站式解决方案
  • 基于大语言模型的代码仓库智能文档生成:RepoAgent实战指南
  • 绝缘臂高空作业车品牌推荐及选择指南:绝缘臂高空作业车、电力局专用高空作业车、绝缘斗臂高空作业车、绝缘曲臂高空作业车选择指南 - 优质品牌商家
  • Weka回归算法实战:从入门到工业级应用
  • 落地台灯怎么选?内行才知道的挑选技巧,家长必看避坑干货
  • 中望CAD2026机械版:将点坐标批量导入
  • 2026小胸聚拢内衣技术解析:莫代尔内裤/菌草内衣/蚕丝内裤/透气内裤/乳胶内衣/儿童内裤/塑身内衣/女士内裤/选择指南 - 优质品牌商家
  • WeChatExporter:iOS微信聊天记录导出与本地化存储解决方案
  • 半导体展会推荐:甄选重磅展会,一站式对接芯领域优质资源 - 品牌2026
  • Hadoop 学习笔记之HDFS
  • Full Page Screen Capture:一键实现完整网页截图的终极解决方案
  • QuantDinger 全网最全保姆级教程:5分钟搭建AI量化系统
  • 2026年4月25日 AI前沿资讯速览
  • 语雀文档批量导出工具:轻松迁移知识资产到本地Markdown
  • 开源数据处理工具Opskat:模块化流水线构建与自动化分析实践
  • 机器学习项目常见陷阱与避坑指南
  • 2026年推荐:粉末冶金高精度齿轮定制厂家深度横评:官方直达与避坑指南 - 精选优质企业推荐官
  • 你不是NPC:在宇宙的数能沙盒里,你拥有最高权限
  • Keras活动正则化:原理、实现与调优实战
  • ARM926EJ-S开发环境搭建与调试优化指南
  • 基于反思工作流的智能翻译代理:原理、实现与优化指南
  • 中国汽车在俄罗斯市场下跌后,日本汽车迎来倍增,新的较量开始了
  • 2026木纹铝扣板技术解析:青岛外墙铝方通/青岛工程铝扣板/青岛异形铝方通/青岛弧形铝方通/青岛木纹铝扣板/青岛木纹铝方通/选择指南 - 优质品牌商家
  • 2026年金水区搬家公司标杆名录:中原区搬家公司/最专业的搬家公司/最便宜的搬家公司/最靠谱的搬家公司/郑州搬家公司/选择指南 - 优质品牌商家
  • 终极指南:如何在Windows上直接安装Android应用而不使用模拟器
  • UniApp蓝牙打印实战指南:移动端标签打印完整解决方案
  • 如何排查SQL存储过程内存溢出_优化大数据量临时表使用