本篇是C语言刷题大杂烩,收集了笔者遇到的认为有价值的题目,本篇会持续更新~~
day01
至少是其他数字两倍的最大数
题目原文:
题意解析:
请你找出数组中的最大元素并检查它是否 至少是数组中每个其他数字的两倍 。如果是,则返回 最大元素的下标 ,否则返回 -1 。
个人思路:
题目要求最大元素大于等于数组其他每个元素的2倍,可能一开始就会直接想遍历数组的所有元素,然后与最大元素一一比较。其实仔细想想,只要最大元素大于等于数组中第二个较大值的2倍就行了,这样就保证了最大元素大于等于数组其他每个元素的2倍。
个人代码:文章来源地址https://www.toymoban.com/news/detail-860677.html
int dominantIndex(int* nums, int numsSize) {
int m1 = -1, m2 = -1;//m1表示最大值,m2表示数组中第二个最大值
int index = -1;//最大值下标
for (int i = 0; i < numsSize; i++) {
if (nums[i] > m1) {
m2 = m1;
m1 = nums[i];
index = i;
}
else if (nums[i] > m2) {
m2 = nums[i];
}
}
return m1 >= m2 * 2 ? index : -1;//三目操作符,值得注意使用
}
两个数组的交集
题目原文:
题目解析:
找出两个数组中相同的元素,存储到动态开辟的新数组中,新数组中的元素是唯一的,不能有重复。
个人思路:
定义一个新数组,把其中一个数组的元素值当作新数组的下标,初始化新数组,这样做的目的是防止数组中的重复元素多次比较。然后把第二个数组的元素值也当作新数组的下标,遍历新数组,如果遍历结果大于0,那么此时下标就是两个元素的交集。
个人代码:
// 两个数组的交集
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize) {
int nums1Cnt[1000] = { 0 };//用于存储、比较两个数组的元素是否相等,
int lessSize = nums1Size < nums2Size ? nums1Size : nums2Size;//节约空间
int* result = (int*)calloc(lessSize, sizeof(int));//动态开辟数组指针
int resultIndex = 0;//动态开辟数组下标
int* tempNums;
int i;
for (i = 0; i < nums1Size; i++) {
nums1Cnt[nums1[i]]++;//解决数组中有重复的元素
}
for (i = 0; i < nums2Size; i++) {
if (nums1Cnt[nums2[i]] > 0) {
result[resultIndex] = nums2[i];
resultIndex++;
nums1Cnt[nums2[i]] = 0;//防止重复元素的比较
}
}
*returnSize = resultIndex;
return result;
}
day02
多数元素
题目原文:
题目解析:
返回数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
个人思路:
投票法。先确定一个投票对象,然后遍历数组,相同元素票数加1,不同元素票数减1。因为多数元素个数多所以票数一定多。当票数为0时,此时说明该投票对象不是多数,更改投票对象。
个人代码:
int majorityElement(int* nums, int numsSize)
{
int ans = 0;//投票对象
int cnts = 0;//票数
for (int i = 0; i < numsSize; i++)
{
if (ans == nums[i])
{
cnts++;
}
else if (cnts == 0)
{
ans = nums[i];
}
else
{
cnts--;
}
}
return ans;
}
字符个数统计
题目原文:
题目解析:
计算字符串中含有的不同字符的个数,多个相同的字符只计算一次
个人思路:
由于字符在 ASCII 码范围内( 0~127 ,包括 0 和 127 ),都是正整数,且多个相同的字符只计算一次,所以我们可以采用把字符当作数组下标的方式来存储,这样就解决了相同字符的问题。
个人代码:
int main()
{
int i, num = 0, len;
char a[1000];
char b[128] = { 0 };
gets(a);
len = strlen(a);
for (i = 0; i < len; i++)
{
if (a[i] >= 0 && a[i] <= 127)
b[a[i]]++;
}
for (i = 0; i < 127; i++)
{
if (b[i] > 0)
num++;
}
printf("%d", num);
return 0;
}
day03
自除数
题目原文:
题目解析:
给定两个整数 left 和 right ,返回一个列表,列表的元素是范围 [left, right] 内所有的 自除数 。
一个数中如果含0,由于0不能作为被除数则该数对0取余不成立,则含0的数不满足题意
个人思路:
1.创建数组:int ret=(int)malloc(sizeof(int)*(right-left+1));
此外,要返回数组大小,在判断时要记录进入数组中元素的大小
2.循环语句:对于left与right之间的元素一一进行判断(用judge函数判断)
3.judge函数:对于一个数temp进行判断:用while语句进行判断,用flag求得被除数,每进行一次取余的判断,temp就除10,此外用num记录初始的数字
个人代码:
bool judge(int temp){
int num,flag;
num=temp;
while(temp>0){
flag=temp%10;
temp/=10;
if(flag==0){
return false;
}
if(num%flag!=0){
return false;
}
}
return true;
}
int* selfDividingNumbers(int left, int right, int* returnSize)
{
int *ret=(int*)malloc(sizeof(int)*(right-left+1));
int count=0;
for(int i=left;i<=right;i++){
if(judge(i)){
ret[count++]=i;
}
}
*returnSize=count;
return ret;
}
除自身以外数组的乘积
题目原文:
题目解析:
求除自身以外数组的乘积,返回到新数组中
个人思路:
前缀后缀法
初始化:创建一个结果数组 ra,并将所有元素初始化为 1。
前缀乘积:从左到右遍历数组,使用变量 pre 累积左侧元素的乘积。
后缀乘积:从右到左遍历数组,使用变量 suf 累积右侧元素的乘积。
组合结果:结合前缀和后缀乘积,存储在结果数组 ra 中。
返回结果:设置返回数组的大小,并返回结果数组 ra
个人代码:
// 数组中除自身以外元素的乘积
int* productExceptSelf(int* nums, int numsSize, int* returnSize)
{
int *ans = malloc(sizeof(int) * numsSize);
*returnSize = numsSize;
ans[0] = 1;
for (int i = 1; i < numsSize; i++)
{
ans[i] = ans[i - 1] * nums[i - 1];
}
int suf = 1;
for (int i = numsSize - 1; i >= 0; i--)
{
ans[i] *= suf;
suf *= nums[i];
}
return ans;
}
day04
不用加减乘除做加法
题目原文:
题目解析:
要解题其实很简单,我们只需要掌握 按位与、按位或、按位异或 的规则即可。
个人思路:
巧用位运算: 1、num1 & num2,与运算,得到的是2个数都是1的位置,如果进行加法,则需要进位,m =(num1 & num2)<< 1,得到进位后的数。
2、num1 ^ num2,异或,得到的是2个数1个为0另一个为1的位置,如果进行加法,则不需要进位。n = num1 ^ num2,此时如果m + n得到的就是两数之和,但不能做加法,此时我们想到了或运算。但如果将m、n直接进行或运算,无法保证不进位,于是我们重复以上的过程。
3、当n与上m得0 的时候,即再也不需要进位了,此时将m | n返回即可。
个人代码:
int Add(int num1, int num2 )
{
// write code here
while (num1)
{ //num1不为0就表示还有进位
int tmp = num1 ^ num2; //计算不算进位的相加结果
num1 = (num1 & num2) <<1;//计算有进位的位置,左移1就将进位移到它该在的位置
num2 = tmp; //将没进位的结果交给num2,直到进位为0,结束计算
}
return num2;
}
找到所有数组中消失的数字
题目原文:
题目解析:
求不在数组中的[1, n]的值,返回新数组。
个人思路:
第一个思路是暴力求解法,遍历[1, n]的值,然后遍历数组的元素一一比较。但是:
第二个思路是哈希表,申请空间ans,作为简单哈希表,当nums[i]出现时,将ans对应的下标至 1 ,记录出现元素,ans[nums[i]] = 1最后遍历数组ans,将未出现的元素下标保存输出,可能会疑问不是申请了额外空间吗?不满足进阶要求,但是我们可以将额外空间和输出空间合并为一个空间,即做输出又做记录
个人代码:
int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize)
{
int * ans = malloc(sizeof(int)* (numsSize+1));//申请空间,作为简易哈希表
for(int i = 0; i< numsSize; i++)
{
ans[nums[i]] = 1;//记录出现元素
}
*returnSize = 0;
for(int i = 1; i <= numsSize; i++)
{
if(ans[i] != 1)//对为出现的元素保存输出
{
ans[(*returnSize)++] = i;
}
}
return ans;
}
day05
完全数计算
题目原文:
题目解析:
求1到n内完全数的个数,完全数:它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。
个人思路:
暴力求解法:遍历1到n,然后再遍历判断是否是完全数。时间复杂度O(n^2)
个人代码:
int main()
{
int n;
while (scanf("%d ", &n) != EOF)
{ // 注意 while 处理多个 case
// 64 位输出请用 printf("%lld") to
int ret = 0;
for(int i = 1;i <= n;i++)
{
int count = 0;
for(int j = 1;j < i;j++)
{
if(i % j == 0)
{
count += j;
}
}
if(count == i)
{
ret++;
}
}
printf("%d\n",ret);
}
return 0;
}
最大连续 1 的个数
题目原文:
题目解析:
给定一个二进制数组 nums , 计算其中最大连续 1 的个数。
个人思路:
暴力求解,遍历数组,如果是1,count++,不是的话,先把count与之前保存的count比较,大的那个存下来,然后count置为0,继续遍历,注意,当循环结束时,还要在比较一次。
个人代码:
int findMaxConsecutiveOnes(int* nums, int numsSize)
{
//1.暴力求解
int count = 0;
int max = 0;
for(int i = 0;i < numsSize;i++)
{
if(nums[i] == 1)
{
count++;
}
else
{
max = max > count ? max : count;
count = 0;
}
}
max = max > count ? max : count;
return max;
}
day06
数字颠倒
题目原文:
题目解析:
要求将这个整数以字符串的形式逆序输出。
个人思路:
1.把输入的数字当做一个字符串进行接收,然后直接从后向前倒序输出。
2.当成数字输入,获得每位并加上’0’,然后直接输出
个人代码:
//1.把输入的数字当做一个字符串进行接收,然后直接从后向前倒序输出。
#include <stdio.h>
int main()
{
char str[32] = {0};
scanf("%s",str);
//gets(str);
for(int i=strlen(str)-1;i>=0;i--)
{
printf("%c",str[i]);
}
printf("\n");
}
//2.当成数字输入,获得每位并加上'0',然后直接输出
#include<stdio.h>
int main(){
int num = 0;
scanf("%d\n",&num);
if(num == 0) printf("%c",'0');
while(num != 0){
printf("%c",num%10+'0');
num/=10;
}
printf("\n");
}
单词倒排
题目原文:
个人思路:
使用了scanf函数的读入指定字符集的功能,只读入大小写字母,遇到非字母的就保存并继续读取,直到读到\n结束,最后倒序输出。
个人代码:
#include <stdio.h>
int main(){
char str[100][22];
int i=0;
int x;
while(1){
x=scanf("%[a-z|A-Z]",str[i]);
if(getchar()=='\n') break;
if(x) i++;
}
for(int j=i;j>=0;j--){
printf("%s ",str[j]);
}
return 0;
}
day07
统计每个月兔子的总数
题目原文:
个人思路:
将兔子分成三类,可育兔子(sum),刚出生的兔子(b),即将成熟的兔子(a)
每个月开始,上个月即将成熟的兔子本月发育成熟:sum += a
并产下等数量的兔子:b=sum
上个月刚出生的兔子即将成熟:a=b
初始数量为1且无幼年兔:sum=1,a=b=0
第三个月才开始繁殖,所以循环直接从第三个月开始算:i=2。
总数量为三种兔子之和:sum+a+b
个人代码:
#include <stdio.h>
int main()
{
int n;
while (scanf("%d", &n) != EOF) { // 注意 while 处理多个 case
// 64 位输出请用 printf("%lld") to
int sum = 1;
int a = 0;
int b = 0;
for(int i = 2;i < n;i++)
{
sum += a;
a = b;
b = sum;
}
printf("%d\n",sum + a + b);
}
return 0;
}
数列的和
题目原文:
个人思路:
暴力求解,对第一个进行平方根运算,然后把结果保留起来,最后求和
个人代码:
#include <stdio.h>
#include <math.h>
int main() {
double n,sum;
int m;
while (scanf("%lf %d", &n, &m) != EOF) { // 注意 while 处理多个 case
// 64 位输出请用 printf("%lld") to
double sum = n;
for(int i = 1;i < m;i++)
{
double a = sqrt(n);
sum += a;
n = a;
}
printf("%.2lf\n",sum);
}
return 0;
}
day08
NC61 两数之和
题目原文:
个人思路:
方法一:暴力枚举
当我们使用遍历整个数组的方式寻找 target - x 时,需要注意到每一个位于 x 之前的元素都已经和 x 匹配过,因此不需要再进行匹配。而每一个元素不能被使用两次,所以我们只需要在 x 后面的元素中寻找 target - x。
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
for (int i = 0; i < numsSize; ++i) {
for (int j = i + 1; j < numsSize; ++j) {
if (nums[i] + nums[j] == target) {
int* ret = malloc(sizeof(int) * 2);
ret[0] = i, ret[1] = j;
*returnSize = 2;
return ret;
}
}
}
*returnSize = 0;
return NULL;
}
方法二:哈希表
使用哈希表,可以将寻找 target - x 的时间复杂度降低到从 O(N)O(N)O(N) 降低到 O(1)O(1)O(1)。
这样我们创建一个哈希表,对于每一个 x,我们首先查询哈希表中是否存在 target - x,然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配。
struct hashTable {
int key;//键
int val;//值
UT_hash_handle hh;
};
struct hashTable* hashtable; // 哈希表指针
struct hashTable* find(int ikey) {
struct hashTable* tmp;
HASH_FIND_INT(hashtable, &ikey, tmp); // 在哈希表中查找指定键的节点
return tmp; // 返回找到的节点指针
}
void insert(int ikey, int ival) {
struct hashTable* it = find(ikey); // 查找指定键的节点
if (it == NULL) { // 如果节点不存在
struct hashTable* tmp = malloc(sizeof(struct hashTable)); // 创建一个新节点
tmp->key = ikey, tmp->val = ival; // 设置节点的键和值
HASH_ADD_INT(hashtable, key, tmp); // 将节点添加到哈希表中
} else { // 如果节点已存在
it->val = ival; // 更新节点的值
}
}
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
hashtable = NULL; // 初始化哈希表
for (int i = 0; i < numsSize; i++) { // 遍历整数数组
struct hashTable* it = find(target - nums[i]); // 查找目标值减去当前元素的差值是否在哈希表中存在
if (it != NULL) { // 如果存在
int* ret = malloc(sizeof(int) * 2); // 创建一个数组用于存储结果
ret[0] = it->val, ret[1] = i; // 设置结果数组的值
*returnSize = 2; // 设置返回结果的大小
return ret; // 返回结果数组
}
insert(nums[i], i); // 将当前元素插入哈希表
}
*returnSize = 0; // 没有找到满足条件的两个数,返回结果大小为 0
return NULL; // 返回空指针
}
题目原文:
个人思路:
暴力求解:先求猜中的,然后再求伪猜中,注意的是防止重复比较的问题,把第二个数组比较的值置为0.
个人代码:
int* masterMind(char* solution, char* guess, int* returnSize)
{
int count = 0;
int count1 = 0;
int* answer = (int*)malloc(sizeof(int) * 2);
*returnSize = 2;
//猜中
for(int i = 0;i < 4;i++)
{
if(solution[i] == guess[i])
{
count++;
}
}
//没猜中
for(int i = 0;i < 4;i++)
{
for(int j = 0;j < 4;j++)
{
if(solution[i] == guess[j])
{
count1++;
guess[j] = 0;
break;
}
}
}
answer[0] = count;
answer[1] = count1 - count;
return answer;
}
添加逗号
题目原文:
题解一:
#include<string.h>
int main() {
char s[20] = {0};
scanf("%s", &s);
int val = strlen(s); //获取字符长度
for (int i = 1; i <= val; i++) { //依次输出字符
printf("%c", s[i - 1]);
//每输出三位数加一个‘,’且输出数不为最后一个数
if ((val - i) % 3 == 0 && i != val) printf(",");
}
return 0;
}
题解二:
#include<stdio.h>
int main()
{
long long int n;
int arr[4]={0};
int sz=0;
scanf("%lld",&n);
int i = 0;
while(n)
{
arr[i++]=n%1000;
n/=1000;
}
for(i=3;i>0;--i)
{
if(arr[i]!=0)
{
printf("%d,",arr[i]);
}
}
if(arr[1]==0)
{
printf("%d",arr[0]);
}
else
printf("%03d",arr[0]);
return 0;
}
删除公共字符
删除公共字符
day09
寻找奇数
题目原文:
个人思路:
单身狗问题,遍历数组,把数组每个元素异或
个人代码:
#include <stdio.h>
int main() {
int n = 0;
scanf("%d",&n);
int arr[n];
int ret = 0;
for(int i = 0;i < n;i++)
{
scanf("%d",&arr[i]);
}
for(int i = 0;i < n;i++)
{
ret ^= arr[i];
}
printf("%d\n",ret);
return 0;
}
NC107 寻找峰值
个人思路:
暴力求解法:
遍历数组,分别判断是否是峰值。文章来源:https://www.toymoban.com/news/detail-860677.html
个人代码:
int findPeakElement(int* nums, int numsLen )
{
int len=numsLen;
for(int i=1;i<len-1;i++)
{
if(nums[i]>nums[i-1]&&nums[i]>nums[i+1])
{
return i;
}
}
if(nums[0]>nums[1])
{
return 0;
}
else if(nums[len-1]>nums[len-2])
{
return len-1;
}
return -1;
}
到了这里,关于“开关是灯的日出日落,日出日落是灯的开关”的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!