“开关是灯的日出日落,日出日落是灯的开关”

本篇是C语言刷题大杂烩,收集了笔者遇到的认为有价值的题目,本篇会持续更新~~

day01

至少是其他数字两倍的最大数

题目原文:

在这里插入图片描述

题意解析:

请你找出数组中的最大元素并检查它是否 至少是数组中每个其他数字的两倍 。如果是,则返回 最大元素的下标 ,否则返回 -1 。

个人思路:

题目要求最大元素大于等于数组其他每个元素的2倍,可能一开始就会直接想遍历数组的所有元素,然后与最大元素一一比较。其实仔细想想,只要最大元素大于等于数组中第二个较大值的2倍就行了,这样就保证了最大元素大于等于数组其他每个元素的2倍。

个人代码:

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 寻找峰值

在这里插入图片描述
个人思路:

暴力求解法:
遍历数组,分别判断是否是峰值。

个人代码:

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;
}

day10

WY49 数对

题目原文:

在这里插入图片描述
个人思路:

分析:
由于需要满足的条件是 x%y>=k,那么y的取值范围显然属于区间[k+1, n],因为如果y<=k,一定不满足x%y>=k这个必要条件。那么我们就根据y的取值范围进行枚举,即对于每一个y来统计满足x%y>=k条件的个数,将答案记录相加即可。现在的问题是对于某个特定的y如何计算满足条件的个数,由于x属于[1,n]区间,我们在将其划分为若干个小区间如下:
[1, 2, …, y]
[y+1, y+2, …, 2y]
[2y+1, 2y+2, …, 3y]

[ty+1, ty+2, …, n]
其中上述的t=n/y。
那么对于上述的前t个区间来说,每个小区间对y取模得到的值就是它在小区间中的下标-1,那么在小区间中找到>=k的个数就很好找了,即个数=y-k。举个例子:y=5,k=3:所以一定有如下区间存在:
[1, 2, 3, 4, 5]
那么显然x%5>=3的个数为5-3=2个,即4和5两个数,其它小区间同理。
那么一共有多少个小区间呢?显然有t=n/y个,然后我们在判断最后一个小区间中有多少个>=k的个数,显然为n%y-k+1个,当然也有可能为0个,所以两者取最大值。那么答案显然易见:对于当前枚举的y来说,有多个的x满足x%y>=k的条件。最后我们将y从k+1一直枚举到n,将每个y得到的满足条件的个数相加即可。
Tips:
(1) 需要特殊判断当k=0的情况,直接就是n*n。
(2) 注意结果需要用long long。

个人代码:

#include<stdio.h>
int main()
{
    //考的是数学只是,暴力求解的话时间复杂度根本不能达到要求,所以我们直接去
    //推出这个数学问题的*********公式********
    //这一这题数据很大,定义成int 时不可以通过的
    long n=0,k=0;
    while(~scanf("%ld %ld",&n,&k))
    {
        if(k==0)
        {
            printf("%ld\n",n*n);
            continue;
        }
        long count=0;
        for(long y=k+1;y<=n;y++)
        {
            long ret=n%y<k?0:n%y-(k-1);
            count+=(y-k)*(n/y)+(ret);
        }
        printf("%ld\n",count);
    }
    return 0;
 }

删除公共字符

删除公共字符

题目原文:

在这里插入图片描述
个人思路:

暴力求解法:

遍历第一个数组,和第二个数组的元素进行比较,如果不相等,就打印出来。

个人代码:

int is_exit(char ch,char arr2[])
{
    int i = 0;
    while(arr2[i])
    {
        if(ch == arr2[i])
        {
            return 1;
        }
        i++;
    }
    return 0;
}
int main() 
{
    char arr1[100];
    char arr2[100];
    gets(arr1);
    gets(arr2);
    int i = 0;
    while(arr1[i])
    {
        if(is_exit(arr1[i],arr2) == 0)
        {
            printf("%c",arr1[i]);
        }

        i++;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Filex;

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值