反转链表【链表】

描述
输入一个链表,反转链表后,输出新链表的表头。

示例

  1. 输入:
  2. {1,2,3}
  3. 返回值:
  4. {3,2,1}

自测

  1. /**
  2. * struct ListNode {
  3. * int val;
  4. * struct ListNode *next;
  5. * };
  6. */
  7. /**
  8. *
  9. * @param pHead ListNode类
  10. * @return ListNode类
  11. */
  12. struct ListNode* ReverseList(struct ListNode* pHead ) {
  13. // write code here
  14. //输入检查
  15. if(pHead == NULL)
  16. return NULL;
  17. struct ListNode* p_index = NULL;
  18. struct ListNode* p_next_orig = NULL;
  19. struct ListNode* p_pre_orig = NULL;
  20. //获取P1,需要注意的是本到题目的pHead就是指向第一个元素
  21. p_index = pHead;
  22. //检查P
  23. while(p_index->next != NULL)
  24. {
  25. //保留原始的下一个元素
  26. p_next_orig = p_index->next;
  27. //重新赋值当前元素的下一个元素
  28. p_index->next = p_pre_orig;
  29. //将前元素作为下一个元素的元前一个元素
  30. p_pre_orig = p_index;
  31. //进入原始下一个元素
  32. p_index = p_next_orig;
  33. }
  34. //将最后一个元素的下一个元素改为原始的上一个元素
  35. p_index->next = p_pre_orig;
  36. //将最后一个元素赋值给头指针的next
  37. pHead = p_index;
  38. return pHead;
  39. }

排序【排序】

描述
给定一个数组,请你编写一个函数,返回该数组排序后的形式。
示例1

  1. 输入:
  2. [5,2,3,1,4]
  3. 复制
  4. 返回值:复制
  5. [1,2,3,4,5]

示例2

输入:
[5,1,6,2,5]
复制
返回值:复制
[1,2,5,5,6]

备注
数组的长度不大于100000,数组中每个数的绝对值不超过10^9109

自测(选择排序)

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 * 将给定数组排序
 * @param arr int整型一维数组 待排序的数组
 * @param arrLen int arr数组长度
 * @return int整型一维数组
 * @return int* returnSize 返回数组行数
 */
int* MySort(int* arr, int arrLen, int* returnSize ) {
    // write code here
    //输入检查
    if(arr == NULL)
        return arr;
     *returnSize = arrLen;
    //选择排序(超时)
    int i = 0;
    int j = 0;
    int max_temp = 0;
    int max_index = 0;

    for(i = 0; i < arrLen -1; i++) 
    {
        //初始化最大值
        max_temp = arr[0];
        max_index = 0;

        for( j = 1; j < arrLen - i; j++)
        {
            //查找最大值
             if( max_temp < arr[j])
             {
                 max_temp = arr[j];
                 max_index = j;
             }
        } 
        //将最大值放到最后
        arr[max_index] = arr[ arrLen - i-1];
        arr[ arrLen - i-1] = max_temp;
    }
    return arr;
}
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 * 将给定数组排序
 * @param arr int整型一维数组 待排序的数组
 * @param arrLen int arr数组长度
 * @return int整型一维数组
 * @return int* returnSize 返回数组行数
 */
int cmpfun(const void *a, const void *b)
{
    return *((int *)a) - *((int *)b);
}

int* MySort(int* arr, int arrLen, int* returnSize ) {
    // write code here
       //输入检查
    if(arr == NULL)
        return arr;
     *returnSize = arrLen;
    //使用快排
    qsort(arr, arrLen, sizeof(int),cmpfun);
    return arr;
}

合并有序数组【归并】【双指针】

描述
给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。你可以假设 nums1 的空间大小等于 m + n,这样它就有足够的空间保存来自 nums2 的元素。
示例 1

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]

示例 2

输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]

提示
nums1.length == m + n
nums2.length == n
0 <= m, n <= 200
1 <= m + n <= 200
-109 <= nums1[i], nums2[i] <= 109
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

自测

#直接合并使用快排
int cmp(const void * a, const void * b)
{
    return *(int *)a - *(int *)b;
}

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
    memcpy((void *)(nums1 + m) ,(void *) nums2, n * 4);
    qsort(nums1, m+n, sizeof(int), cmp);
}
#使用逆向双指针(先在num1中排最大值)

根据字符出现频率排序
给定一个字符串,请将字符串里的字符按照出现的频率降序排列。
示例 1
输入:
“tree”
输出:
“eert”
解释:
‘e’出现两次,’r’和’t’都只出现一次。
因此’e’必须出现在’r’和’t’之前。此外,”eetr”也是一个有效的答案。
示例 2
输入:
“cccaaa”
输出:
“cccaaa”
解释:
‘c’和’a’都出现三次。此外,”aaaccc”也是有效的答案。
注意”cacaca”是不正确的,因为相同的字母必须放在一起。
示例 3
输入:
“Aabb”
输出:
“bbAa”
解释:
此外,”bbaA”也是一个有效的答案,但”Aabb”是不正确的。
注意’A’和’a’被认为是两种不同的字符。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-characters-by-frequency
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

自测

char * frequencySort(char * s){
    if(s == NULL)
        return s;
    int acs_table[256] = {0};

    int  s_lens =  strlen(s);
    //统计字符个数
    for (int i = 0; i < s_lens; i++)
    {
        acs_table[s[i]]++;
    }

    long sorted_index = 0;
    for (int j = 0; j < 256; j++ )
    {
        int max_index = 0;
        long max_frequence = 0;

        //找到最大频率
        for(int i = 0; i < 256; i++)
        {
            //记录频率最大的字符
            if(acs_table[i] > max_frequence)
            {
                max_index = i;
                max_frequence = acs_table[i];
            }
        }

        if(max_frequence ==0)
            continue;

        //排列最大的字符
        for(int i = 0; i < max_frequence; i++) 
            s[sorted_index++] = max_index;

        //清空最大的字符
        acs_table[max_index] = 0;

        //
        if(sorted_index >= s_lens)
         break;
    }
    return s;
}

image.png

汽水瓶【递归】

描述
有这样一道智力题:“某商店规定:三个空汽水瓶可以换一瓶汽水。小张手上有十个空汽水瓶,她最多可以换多少瓶汽水喝?”答案是5瓶,方法如下:先用9个空瓶子换3瓶汽水,喝掉3瓶满的,喝完以后4个空瓶子,用3个再换一瓶,喝掉这瓶满的,这时候剩2个空瓶子。然后你让老板先借给你一瓶汽水,喝掉这瓶满的,喝完以后用3个空瓶子换一瓶满的还给老板。如果小张手上有n个空汽水瓶,最多可以换多少瓶汽水喝?
来源:牛客网
链接:https://www.nowcoder.com/questionTerminal/fe298c55694f4ed39e256170ff2c205f?answerType=1&f=discussion

输入描述:

输入文件最多包含10组测试数据,每个数据占一行,仅包含一个正整数n(1<=n<=100),表示小张手上的空汽水瓶数。n=0表示输入结束,你的程序不应当处理这一行。

输出描述:

对于每组测试数据,输出一行,表示最多可以喝的汽水瓶数。如果一瓶也喝不到,输出0。

示例

输入
3 10 81 0 

输出
1 5 40

自测

#include <stdio.h>
#include <string.h>

//递归解决问题
int solving( int n)
{   
    if(n <=1)
        return 0;

    if(n == 2)
        return 1;

    int this_water = n/3;
    int next_bottle = n/3 + n%3;

    if( next_bottle == 1 )
        return this_water;
    else
    {
        int next_water = solving( next_bottle);
        return (next_water + this_water);
    }

}

int main()
{
   int input_array[10] = {0};
   int  resolv_array[10] = {0};
   int input_num = 0;
   int input_temp = 0;
    //保存用户输入数据
   while(scanf("%d", &input_temp) == 1)
   {
       if(input_temp == 0 || input_temp > 100)
       {
           break;
       }
       input_array[input_num] = input_temp;
       input_num++;
       if(input_num >= 10)
           break;
   }
   // 解决数组
    for(int i=0; i < input_num; i++ )
    {
       resolv_array[i] = solving(  input_array[i]);
        printf("%d\n", resolv_array[i] );
    }
   return 0;
}

明明的随机数

描述
明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤1000),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作(同一个测试用例里可能会有多组数据(用于不同的调查),希望大家能正确处理)。

注:测试用例保证输入参数的正确性,答题者无需验证。测试用例不止一组。

当没有新的输入时,说明输入结束。

输入描述
注意:输入可能有多组数据(用于不同的调查)。每组数据都包括多行,第一行先输入随机整数的个数N,接下来的N行再输入相应个数的整数。具体格式请看下面的”示例”。

输出描述
返回多行,处理后的结果

实例

输入例子1:
3
2
2
1
11
10
20
40
32
67
40
20
89
300
400
15

输出例子1:
1
2
10
15
20
32
40
67
89
300
400

例子说明1:
输入解释:
第一个数字是3,也即这个小样例的N=3,说明用计算机生成了3个1到1000之间的随机整数,接下来每行一个随机数字,共3行,也即这3个随机数字为:
2
1
1
所以第一个小样例的输出为:
1
2
第二个小样例的第一个数字为11,也即...(类似上面的解释)...
所以第二个小样例的输出为:
10
15
20
32
40
67
89
300
400
所以示例1包含了两个小样例!!

自测

/*
 * main.c
 *
 *  Created on: Aug 27, 2021
 *      Author: mate
 */
#include <stdio.h>
#include <string.h>

int main()
{
    int input_array[1000] = {0};
    int input_num = 0;
    int input_temp = 0;
    int nums = 0;

    while( scanf("%d", &nums) == 1 )
    {
        //保存用户输入数据
        input_num = 0;
        memset(input_array, 0, sizeof(input_array));
        while(scanf("%d", &input_temp) == 1)
        {
            input_array[input_temp - 1] = 1;
            input_num ++;
            if(input_num == nums)
                break;
        }

        //输出
        for(int i=0; i < 1000 && input_num > 0; i++ )
        {
            if(input_array[i] == 1)
            {
                printf("%d\n",i+1);
                input_num --;
            }

        }

    }

    return 0;
}

跳台阶【动态规划】【递归】【数学】

描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
示例1

输入:
2

返回值:
2

示例2

输入:
7

返回值:
21

方法一:递归
题目分析,假设f[i]表示在第i个台阶上可能的方法数。逆向思维。如果我从第n个台阶进行下台阶,下一步有2中可能,一种走到第n-1个台阶,一种是走到第n-2个台阶。所以f[n] = f[n-1] + f[n-2].
那么初始条件了,f[0] = f[1] = 1。
所以就变成了:f[n] = f[n-1] + f[n-2], 初始值f[0]=1, f[1]=1,目标求f[n]

int Fibonacci(int n) {
    if (n<=1) return 1;
    return Fibonacci(n-1) + Fibonacci(n-2);
}

方法二:动态规划
那就用动态规划,优化掉递归栈空间。
方法二是从上往下递归的然后再从下往上回溯的,最后回溯的时候来合并子树从而求得答案。
那么动态规划不同的是,不用递归的过程,直接从子树求得答案。过程是从下往上。

int jumpFloor(int number ) {
    // write code here
  int last_jump_way = 1;
  int pre_last_jump_way = 0;  
  int jump_way = 0;
  int step;
   for(step = 1; step <= number; step++)
   {
       jump_way = last_jump_way + pre_last_jump_way;
       //更新前两组
       pre_last_jump_way = last_jump_way;
       last_jump_way = jump_way;
   }
    return jump_way;
}

LRU实现【】

描述
设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为K,并有如下两个功能
1. set(key, value):将记录(key, value)插入该结构
2. get(key):返回key对应的value值

提示:
1.某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的,然后都会刷新缓存。
2.当缓存的大小超过K时,移除最不经常使用的记录。
3.输入一个二维数组与K,二维数组每一维有2个或者3个数字,第1个数字为opt,第2,3个数字为key,value
若opt=1,接下来两个整数key, value,表示set(key, value)
若opt=2,接下来一个整数key,表示get(key),若key未出现过或已被移除,则返回-1
对于每个opt=2,输出一个答案

4.为了方便区分缓存里key与value,下面说明的缓存里key用””号包裹

进阶:你是否可以在O(1)的时间复杂度完成set和get操作
示例1

输入:
[[1,1,1],[1,2,2],[1,3,2],[2,1],[1,4,4],[2,2]],3
复制
返回值:复制
[1,-1]
说明:
[1,1,1],第一个1表示opt=1,要set(1,1),即将(1,1)插入缓存,缓存是{"1"=1} 
[1,2,2],第一个1表示opt=1,要set(2,2),即将(2,2)插入缓存,缓存是{"1"=1,"2"=2} 
[1,3,2],第一个1表示opt=1,要set(3,2),即将(3,2)插入缓存,缓存是{"1"=1,"2"=2,"3"=2} [2,1],第一个2表示opt=2,要get(1),返回是[1],因为get(1)操作,缓存更新,缓存是{"2"=2,"3"=2,"1"=1} 
[1,4,4],第一个1表示opt=1,要set(4,4),即将(4,4)插入缓存,但是缓存已经达到最大容量3,移除最不经常使用的{"2"=2},插入{"4"=4},缓存是{"3"=2,"1"=1,"4"=4}
[2,2],第一个2表示opt=2,要get(2),查找不到,返回是[1,-1]

示例2

输入:
[[1,1,1],[1,2,2],[2,1],[1,3,3],[2,2],[1,4,4],[2,1],[2,3],[2,4]],2
复制
返回值:复制
[1,-1,-1,3,4]

备注:
1 \leq K \leq N \leq 10^51≤K≤N≤105
-2 \times 10^9 \leq x,y \leq 2 \times 10^9−2×109≤x,y≤2×109

数组换成map最好

/**
 * lru design
 * @param operators int整型二维数组 the ops
 * @param operatorsRowLen int operators数组行数
 * @param operatorsColLen int* operators数组列数
 * @param k int整型 the k
 * @return int整型一维数组
 * @return int* returnSize 返回数组行数
 */
struct lru_elemnt {
    int value;
    int lru_counter;
    char get_index;
};

//设置未使用计数
void set_lru_counter (struct lru_elemnt * lru_elemnts)
{
    for(int i = 0; i< 100000; i++)
    {
       if(lru_elemnts[i].value != -1) 
           lru_elemnts[i].lru_counter ++;
    }
}

//检查最久未使用
void check_lru (struct lru_elemnt * lru_elemnts, int max_k)
{
    for(int i = 0; i< 100000; i++)
    {
       if(lru_elemnts[i].lru_counter <=  max_k || lru_elemnts[i].lru_counter ==  2*max_k)
           continue;
        lru_elemnts[i].value = -1;
        lru_elemnts[i].lru_counter = 2*max_k;
        break;
    }
}

int* LRU(int** operators, int operatorsRowLen, int* operatorsColLen, int k, int* returnSize ) {

    static int k_counter = 0;
    static int get_counter = 0;
    static struct lru_elemnt lru_elemnts[500000];
    static int get_elemnts[500000];
      // write code here
    //初始化
    for(int i = 0; i< 100000; i++)
    {
        lru_elemnts[i].value = -1;
         lru_elemnts[i].lru_counter = 2*k;
         lru_elemnts[i].get_index = 0;
    }


    for(int i = 0; i < operatorsRowLen; i++)
    {
        //set
        if(operatorsColLen[i] == 3 && operators[i][0] ==1 )
             lru_elemnts[operators[i][1]].value = operators[i][2];

        //get
        if(operatorsColLen[i] == 2 && operators[i][0] ==2)
        {
            get_elemnts[get_counter] =  lru_elemnts[operators[i][1]].value;
            get_counter++;
        }

         //设置计数
        if(lru_elemnts[operators[i][1]].value != -1)
        {
            lru_elemnts[operators[i][1]].lru_counter = 0;
            set_lru_counter(lru_elemnts);
        }

         //检查最久未使
         check_lru (lru_elemnts, k);
    }

    //输出GET
    *returnSize = get_counter;
    return get_elemnts;
}

NC105 二分查找-II【查找】

描述

请实现有重复数字的升序数组的二分查找

给定一个 元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的第一个出现的target,如果目标值存在返回下标,否则返回 -1

示例1
输入:
[1,2,4,4,5],4
复制
返回值:复制
2 
说明:
从左到右,查找到第1个为4的,下标为2,返回2

示例2
输入:
[1,2,4,4,5],3
复制
返回值:复制
-1

示例3
输入:
[1,1,1,1,1],1
复制
返回值:
�
0

自测
确保只剩下两个元素

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 如果目标值存在返回下标,否则返回 -1
 * @param nums int整型一维数组 
 * @param numsLen int nums数组长度
 * @param target int整型 
 * @return int整型
 */
int search(int* nums, int numsLen, int target ) {
    // write code here
    if(numsLen ==0 || target < nums[0] || target > nums[numsLen-1])
        return -1;
    if(target == nums[0] )
        return 0;

   int first_index = 0;
   int end_index = numsLen-1;
   int  mid_index = (first_index + end_index)/2;

    while(numsLen  != 1)
    {
        mid_index = (first_index + end_index)/2;
        if(nums[mid_index] >= target ) 
            end_index = mid_index;
        else
            first_index = mid_index +1;

        numsLen = end_index - first_index +1;
    }

    if(nums[first_index] == target)
        return first_index;
    else
         return end_index;
}

NC7 买卖股票的最好时机

描述

假设你有一个数组,其中第\ i i 个元素是股票在第\ i i 天的价格。
你有一次买入和卖出的机会。(只有买入了股票以后才能卖出)。请你设计一个算法来计算可以获得的最大收益。

示例1
输入:
[1,4,2]
复制
返回值:复制
3

示例2
输入:
[2,4,1]
复制
返回值:
�

自测
int maxProfit(int *prices,int pricesSize){
    if(prices == NULL || pricesSize == 0)
        return 0;

    int min = prices[0];
    int maxprofit = -1;

    for(int i = 0;i < pricesSize; ++i){
        //min用来维护历史的最小值
        if(min > prices[i])
            min = prices[i];
        //max用来管理最大的利润
        if(maxprofit < prices[i] - min)
            maxprofit = prices[i] - min;
    }
    return max;
}

26. 删除有序数组中的重复项【双指针】

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
说明
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}

示例 1

输入:nums = [1,1,2]
输出:2, nums = [1,2]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

提示

0 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums 已按升序排列

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

自测
int removeDuplicates(int* nums, int numsSize){

    if(numsSize == 0)
        return 0;
    int fast_index = 1;
    int slow_index = 0;

    for( ; fast_index < numsSize; fast_index++ )
    {
        if(nums[fast_index] != nums[slow_index])
         {
            slow_index++;
            nums[slow_index] = nums[fast_index];
         }

    }

  return ++slow_index;

}

NC88 寻找第K大【排序】

描述

有一个整数数组,请你根据快速排序的思路,找出数组中第 常见编程试题 - 图2大的数。
给定一个整数数组 常见编程试题 - 图3,同时给定它的大小n和要找的 常见编程试题 - 图4,请返回第 常见编程试题 - 图5大的数(包括重复的元素,不用去重),保证答案存在。
要求时间复杂度 常见编程试题 - 图6

示例1
输入:
[1,3,5,2,2],5,3 
复制
返回值:复制
2

示例2
输入:
[10,10,9,9,8,7,5,6,4,3,4,2],12,3
复制
返回值:复制
9 
说明:
去重后的第3大是8,但本题要求包含重复的元素,不用去重,所以输出9

自测
/**
 * 
 * @param a int整型一维数组 
 * @param aLen int a数组长度
 * @param n int整型 
 * @param K int整型 
 * @return int整型
 */
   int cmp(const void *a, const void *b)
   {
       return (*(int *)b -  *(int *)a);
   }

int findKth(int* a, int aLen, int n, int K ) {
    // write code here
    if(n <=0 || K < 1)
        return 0;
    //排序
    qsort(a, aLen, sizeof(int),cmp);

    //取下标
    return a[K-1];
}

NC19 子数组的最大累加和问题【动态规划】

描述

给定一个数组arr,返回子数组的最大累加和
例如,arr = [1, -2, 3, 5, -2, 6, -1],所有子数组中,[3, 5, -2, 6]可以累加出最大的和12,所以返回12.
题目保证没有全为负数的数据
[要求]
时间复杂度为O(n)O(n),空间复杂度为O(1)O(1)

示例1
输入:
[1, -2, 3, 5, -2, 6, -1]
复制
返回值:复制
12

备注
1 \leq N \leq 10^51≤N≤105
|arr_i| \leq 100∣arri∣≤100

自测
/**
 * max sum of the subarray
 * @param arr int整型一维数组 the array
 * @param arrLen int arr数组长度
 * @return int整型
 */

//动态规划
int maxsumofSubarray(int* arr, int arrLen ) {
    // write code here
    int max_sum = 0;
    int sum = 0;

    for(int i = 0; i < arrLen; i++)
    {
        sum +=  arr[i];
        if(sum < 0) 
            sum = 0;            //抛弃小的值
        if(sum > max_sum)
            max_sum = sum;
    }
    return max_sum;
}

HJ1 字符串最后一个单词的长度【 数组】【字符串】

描述

计算字符串最后一个单词的长度,单词以空格隔开,字符串长度小于5000。

输入描述:
输入一行,代表要计算的字符串,非空,长度小于5000。

输出描述:
输出一个整数,表示输入字符串最后一个单词的长度。

示例1
输入:
hello nowcoder
复制
输出:
8
复制
说明:
最后一个单词为nowcoder,长度为8

自测
#include <stdio.h>
#include <string.h>

int main()
{
    char src[5000]= {0};
    fgets(src, sizeof(src), stdin);

    //输入检查
    int src_len = strlen(src);
    if(src_len > 5000 )
    {
        printf("error");
        return -1;
    }
    //查找最后一个空格
    int index= 0;
    for(int i = src_len; i >= 0; i--){
        if(src[i-1] == '\n')
            src[i-1] = 0;
        if(src[i-1] == ' ')
        {
            index = i;
            break;
        } 

    }
    printf("%d", (int)strlen(src + index));
    return 0;
}

统计字符出现的次数【字符串】

描述

写出一个程序,接受一个由字母、数字和空格组成的字符串,和一个字母,然后输出输入字符串中该字母的出现次数。不区分大小写,字符串长度小于500。

输入描述:
第一行输入一个由字母和数字以及空格组成的字符串,第二行输入一个字母。

输出描述:
输出输入字符串中含有该字符的个数。

示例1

输入:
ABCabc
A
复制
输出:
2

自测
#include <stdio.h>
#include <string.h>

int main()
{
    char temp = 0;
    char table[255] = {0};

    while((temp =getchar()) != EOF)
    {
        //小写字母转大写
        if( temp >= 'a')
            temp -= 'a' - 'A' ; 
        table[temp] ++;
        if(temp == '\n')
        {
            temp =getchar();  
         //小写字母转大写s
             if( temp >= 'a')
            temp -= 'a' - 'A' ; 
            break;
        } 
    }
    printf("%d", table[temp] );
}

大数加法【字符串】

描述

以字符串的形式读入两个数字,编写一个函数计算它们的和,以字符串形式返回。
(字符串长度不大于100000,保证字符串仅由’0’~’9’这10种字符组成)

示例1
输入:
"1","99"
复制
返回值:复制
"100" 
说明:
1+99=100


自测
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 * 计算两个数之和
 * @param s string字符串 表示第一个整数
 * @param t string字符串 表示第二个整数
 * @return string字符串
 */
/*
num = 0~9
*/
char num2char (int num )
{
    return  (('0' - 0) + num );
}

int char2num(char a)
{
    return  (a- ('0' - 0));
}


char* solve(char* s, char* t ) {
    // write code here
    int sLen = strlen(s);
    int tLen = strlen(t);

    int maxLen = 0;
    if(sLen >= tLen)
        maxLen = sLen+5;
    else
         maxLen = tLen+5;

    char *result = (char *)malloc(maxLen);
    memset(result, 0, maxLen);
    int i=0;
    int is_full = 0;
    int a,b,x,y;
    while(sLen >0 ||  tLen > 0  ||  is_full)
    {
        x = 0;
        y = 0;
        if(sLen >0)
        {
            a = s[sLen -1];
            x = char2num(a);
            sLen--;
        }

        if(tLen > 0)
        {
            b= t[tLen-1];
            y= char2num(b);
            tLen--;
        }

        result[i]= num2char( (x + y + is_full) % 10 );
        is_full =(x +  y + is_full) / 10;
        i++;
    }

    maxLen =  strlen(result);
    for(int i = 0; i < maxLen/2; i++)
    {
        a = result[i];
        result[i] = result[maxLen -1-i];
        result[maxLen -1-i] =a;
    }
    return result;
}

HJ4 字符串分隔【字符串】

描述

•连续输入字符串,请按长度为8拆分每个字符串后输出到新的字符串数组;
•长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。

输入描述:

连续输入字符串(输入多次,每个字符串长度小于100)

输出描述:

输出到长度为8的新字符串数组

示例1
输入:
abc
123456789

输出:
abc00000
12345678
90000000

自测

#include<stdio.h>
#include<string.h>

int main()
{
    char s_temp[9] = {0};
    memset(s_temp, '0', 8);
    char s_index =0;
    char c_temp = 0;
    while( (c_temp = getchar()) != EOF)
    {
        if(c_temp == '\n' )
        {
            if( s_index > 0)
            {
                printf("%s\n", s_temp);
                s_index = 0;
                memset(s_temp, '0', 8);
            }
           continue;

        } 

        s_temp[s_index] = c_temp;
        s_index ++;
        if(s_index == 8 )
        {
             printf("%s\n", s_temp);
            s_index = 0;
            memset(s_temp, '0', 8);
            continue;
        }
    }
      return 0;
}

HJ6 质数因子【数学】

描述
功能:输入一个正整数,按照从小到大的顺序输出它的所有质因子(重复的也要列举)(如180的质因子为2 2 3 3 5 )
最后一个数后面也要有空格

输入描述:
输入一个long型整数
输出描述:
按照从小到大的顺序输出它的所有质数的因子,以空格隔开。最后一个数后面也要有空格。

示例1

输入:
180
复制
输出:
2 2 3 3 5

自测

#include<stdio.h>

int main()
{
    long in = 0;
    scanf("%ld",&in);

    long ope = in;
    int i = 2;

    while( i <= ope && i*i <= in )
    {
        //一个因子多次计算
        while(ope % i == 0)
        {
            printf("%d ",i);
            ope /=i ;
        }
        i++;
    }

   //如果遍历完了i~sqrt(in),ope还未变成1,则说明有一个较大的质因子,即为剩余in本身,存储即可
    if(ope > 1)
        printf("%d ", ope);
}

字符集合【字符串】

输入一个字符串,求出该字符串包含的字符集合

输入描述

每组数据输入一个字符串,字符串最大长度为100,且只包含字母,不可能为空串,区分大小写。

输出描述

每组数据一行,按字符串原有的字符顺序,输出字符集合,即重复出现并靠后的字母不输出。

输入例子1:
abcqweracb
输出例子1:
abcqwer

自测
/*
 ============================================================================
 Name        : displayArr.c
 Author      : 
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */
#include <stdio.h>
#include <string.h>

int is_record(char temp, char * arr, int arrLen, int recodNum)
{
    if(recodNum > arrLen)
        return -1;

    for(int i = 0; i< recodNum; i++)
    {
        if(arr[i] == temp)
            return 1;
    }
    return 0;
}

int main() {
    char arr[110] = {0};
    char temp = 0;
    int record = 0;

    while( (temp = getchar()) != EOF)
    {
        if(temp == '\n')
        {
             printf("%s\n",arr);
             record =0;
             memset(arr, 0, 110);
            continue;
        }
        //若是未记录,则进行记录
        if(is_record(temp, arr, 110, record) == 0)
        {
            arr[record] = temp;
            record ++;
        }
    }
    return 0;
}

删字符

有一个数组a[N]顺序存放0~N-1,要求每隔两个数删掉一个数,到末尾时循环至开头继续进行,求最后一个被删掉的数的原始下标位置。以8个数(N=7)为例:{0,1,2,3,4,5,6,7},0->1->2(删除)->3->4->5(删除)->6->7->0(删除),如此循环直到最后一个数被删除。

输入描述

每组数据为一行一个整数n(小于等于1000),为数组成员数,如果大于1000,则对a[999]进行计算。

输出描述

一行输出最后一个被删掉的数的原始下标位置。

输入例子1:
8
输出例子1:
6

自测
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
    int arrLen =0;
    while( scanf("%d", &arrLen)!=EOF)
    {
        if(arrLen > 1000)
            arrLen = 1000;
        int * arr = ( int *)malloc(arrLen * sizeof(int));
        memset(arr, 0, sizeof(int) * arrLen);

        int rmin  = arrLen;
        char dele_index = 0;
        int fron_index = 0;
        int last_delet_index = 0;
        while( rmin > 0)
        {    //寻找删除位置
            if(arr[fron_index] != -1)
                dele_index ++;
            //执行删除
            if(dele_index == 3)
            {
                while( arr[fron_index] == -1)
                    fron_index++;
                //删除
                arr[fron_index] = -1;
                dele_index =0;
                rmin--;
                last_delet_index = fron_index;
            }

            fron_index ++;
            if(fron_index == arrLen)
                fron_index = 0;

        }
        printf("%d\n", last_delet_index);
        free(arr);
    }
    return 0;
}

HJ31 单词倒排

描述

对字符串中的所有单词进行倒排。

说明:

1、构成单词的字符只有26个大写或小写英文字母;

2、非构成单词的字符均视为单词间隔符;

3、要求倒排后的单词间隔符以一个空格表示;如果原字符串中相邻单词间有多个间隔符时,倒排转换后也只允许出现一个空格间隔符;

4、每个单词最长20个字母;

输入描述:
输入一行以空格来分隔的句子

输出描述:
输出句子的逆序

示例1
输入:
I am a student
复制
输出:
student a am I
复制
示例2
输入:
$bo*y gi!r#l
复制
输出:
l r gi y bo

自测
#include <stdio.h>

int main()
{
    char temp = 0;
    char oneSpace = 0;
    char str[255][22] ;
    memset(str, 0, sizeof(str));
    char changeLine = 0;
    char partNum = 0;
    char charNum = 0;

    while( (temp = getchar()) != EOF)
    {
        if( (temp >= 'a' && temp <= 'z') || (temp >= 'A' && temp <= 'Z'))
        {

            str[partNum][charNum] = temp;
            charNum ++;
            oneSpace = 0;
        }
        else if( oneSpace == 0)
        {
            partNum++;
            charNum =0;
            oneSpace = 1;
        }
    }

     for(int i = partNum - 1; i >= 0; i--)
         printf("%s ", str[i]);

    return 0;
}

HJ39 判断两个IP是否属于同一子网

描述

子网掩码是用来判断任意两台计算机的IP地址是否属于同一子网络的根据。
子网掩码与IP地址结构相同,是32位二进制数,其中网络号部分全为“1”和主机号部分全为“0”。利用子网掩码可以判断两台主机是否中同一子网中。若两台主机的IP地址分别与它们的子网掩码相“与”后的结果相同,则说明这两台主机在同一子网中。
示例:
I P 地址 192.168.0.1
子网掩码 255.255.255.0
转化为二进制进行运算:
I P 地址 11000000.10101000.00000000.00000001
子网掩码 11111111.11111111.11111111.00000000
AND运算 11000000.10101000.00000000.00000000
转化为十进制后为:
192.168.0.0

I P 地址 192.168.0.254
子网掩码 255.255.255.0

转化为二进制进行运算:
I P 地址 11000000.10101000.00000000.11111110
子网掩码 11111111.11111111.11111111.00000000
AND运算 11000000.10101000.00000000.00000000
转化为十进制后为:
192.168.0.0
通过以上对两台计算机IP地址与子网掩码的AND运算后,我们可以看到它运算结果是一样的。均为192.168.0.0,所以这二台计算机可视为是同一子网络。

输入一个子网掩码以及两个ip地址,判断这两个ip地址是否是一个子网络。
若IP地址或子网掩码格式非法则输出1,若IP1与IP2属于同一子网络输出0,若IP1与IP2不属于同一子网络输出2。

注:
有效掩码与IP的性质为:
1. 掩码与IP每一段在 0 - 255 之间
2. 掩码的二进制字符串前缀为网络号,都由‘1’组成;后缀为主机号,都由’0’组成

输入描述:

多组输入,一组3行,第1行是输入子网掩码、第2,3行是输入两个ip地址

输出描述:

若IP地址或子网掩码格式非法则输出1,若IP1与IP2属于同一子网络输出0,若IP1与IP2不属于同一子网络输出2

示例1
输入:
255.255.255.0
192.168.224.256
192.168.10.4
255.0.0.0
193.194.202.15
232.43.7.59
255.255.255.0
192.168.0.254
192.168.0.1

输出:
1
2
0

说明:
对于第一个例子:
255.255.255.0
192.168.224.256
192.168.10.4
其中IP:192.168.224.256不合法,输出1

对于第二个例子:
255.0.0.0
193.194.202.15
232.43.7.59
2个与运算之后,不在同一个子网,输出2

对于第三个例子,2个与运算之后,如题目描述所示,在同一个子网,输出0

自测
#include <stdio.h>
#include <string.h>

#define MASK  1
#define IP    0

unsigned int arr2int (unsigned char *arr, int arrLen)
{
    unsigned long temp = 0 ;
    for(int i = 0; i < arrLen; i++)
    {
        temp <<=8;
        temp  |= arr[i];
    }
    return temp;
}


//合法性检查
int is_legal( char *ip, int is_mask)
{
    unsigned char buf[4] = {0};
    int j = 0;

    unsigned char arry_temp[32] = {0};
    strcpy(arry_temp, ip);
    char *strtemp = NULL;
    strtemp = strtok(arry_temp, ".");

    while(strtemp !=NULL)
    {
        if( atoi(strtemp) > 255 || atoi(strtemp) <0)
             return 1;
        buf[j] = atoi(strtemp); 
        j++;
       strtemp = strtok(NULL, ".");
    }

    if(is_mask == MASK)
    {
       unsigned int max_mask = 0xffffffff;
        while(( max_mask  <<= 1) > 0 )
        {
            if(arr2int (buf, 4)  ==  max_mask)
                return 0;
        } 
       return 1;
    }

    return 0;
}

//转为unsigned char
unsigned char * str2arr(char  *str, unsigned char * result)
{
    char temp[8] = {0};
    char temp_index = 0;
    int i = 0;
    int j =0;
      for( ; i< strlen(str); i++)
    {
        if(str[i] >= '0' && str[i] <= '9')
        {
            temp[temp_index] = str[i];
            temp_index ++;
        }
        else
        {
            result[j] = atoi(temp);
            j++;
            temp_index =0;
            memset(temp, 0, 8);
        }
    }
    return  result;
}

//判断是否是统一网段
int is_samenet(char *mask, char *ip1, char *ip2)
{
    //合法性检查
   if( is_legal( mask, MASK) || is_legal( ip1, IP)|| is_legal( ip2, IP))
       return  1;

    //转为unsigned char

    unsigned char mask_int[4] = {0};
    unsigned char ip1_int[4] = {0};
    unsigned char ip2_int[4] = {0};
    str2arr(mask, mask_int);
    str2arr(ip1, ip1_int);    
    str2arr(ip2, ip2_int);

    //比较
    for(int i = 0; i < 4; i++)
    {
       if( (mask_int[i] & ip1_int[i]) != (mask_int[i] & ip2_int[i]))
         return 2;
    }
    return 0;

}


int main()
{
  unsigned char mask[32] = {0};
  unsigned char ip_1[32] = {0}; 
  unsigned  ip_2[32] = {0}; 


   //获取掩码
   while(scanf("%s", mask) != EOF)
   {
       scanf("%s", ip_1);
       scanf("%s", ip_2);
       printf("%d\n", is_samenet(mask, ip_1, ip_2));
   }
  return 0;
}

判断链表中是否有环【链表】【双指针】

如果有环则返回true,否则返回false。
数据范围:链表长度 常见编程试题 - 图7,链表中任意节点的值满足 常见编程试题 - 图8
要求:空间复杂度 常见编程试题 - 图9,时间复杂度 常见编程试题 - 图10
输入分为2部分,第一部分为链表,第二部分代表是否有环,然后回组成head头结点传入到函数里面。-1代表无环,其他的数字代表有环,这些参数解释仅仅是为了方便读者自测调试。实际在编码时读入的是链表的头节点。

示例1
输入:
{3,2,0,-4},1
复制
返回值:复制
true
说明:
第一部分{3,2,0,-4}代表一个链表,第二部分的1表示,-4到位置1,即-4->2存在一个链接,组成传入的head为一个带环的链表 ,返回true

自测

/**
 * struct ListNode {
 *    int val;
 *    struct ListNode *next;
 * };
 */

/**
 * 
 * @param head ListNode类 
 * @return bool布尔型
 */
int hasCycle(struct ListNode* head) {
  struct ListNode *slow = head, *fast = head;
  while (fast && fast->next) {
    slow = slow->next;
    fast = fast->next->next;
    if (slow == fast) return 1;
  }
  return 0;
}