• C语言练习8(巩固提升)


    C语言练习8


    前言
     奋斗是曲折的,“为有牺牲多壮志,敢教日月换新天”,要奋斗就会有牺牲,我们要始终发扬大无畏精神和无私奉献精神。奋斗者是精神最为富足的人,也是最懂得幸福、最享受幸福的人。正如马克思所讲:“历史承认那些为共同目标劳动因而自己变得高尚的人是伟大人物;经验赞美那些为大多数人带来幸福的人是最幸福的人”。

    编程题

    一,编写一个函数,计算字符串中含有的不同字符的个数。字符在 ASCII 码范围内( 0~127 ,包括 0 和 127 ),换行
    表示结束符,不算在字符里。不在范围内的不作统计。多个相同的字符只计算一次
    例如,对于字符串 abaca 而言,有 a、b、c 三种不同的字符,因此输出 3 。
    数据范围: 0 <= n <= 500
    输入描述:输入一行没有空格的字符串。
    输出描述:输出 输入字符串 中范围在(0~127,包括0和127)字符的种数。

    OJ链接【牛客网题号: HJ10 字符个数统计】【难度:简单】
    示例:
    输入:abc 输入:aaa
    输出:3 输出:1

    💡分析:

    这道题思路比较简单,因为题目圈定出现的字符都是 ascii 值小于127的字符,因此只需要定义一个标记数组大小为127 ,然后将字符作为数组下标在数组中进行标记,若数组中没有标记过表示第一次出现,进行计数,否则表示重复字符。
    示例:查表法, “aca” ,首先把a字符( ascii 值为 97 )作为下标,将标记数组的第 97 位置 1 ,下次如果还有 a 字符出现,到下标 ‘a’ 或者 97 的位置一看是1就表示a已经统计过了。

    🔑 代码实现
    //HJ10 字符个数统计
    #include
    int main()
    {
    	char tmp[501] = { 0 };
    	while (~scanf("%s", tmp))
    	{
    		int count = 0;
    		char table[128] = { 0 };
    		char* ptr = tmp;
    		while (*ptr != '\0')
    		{
    			if (table[*ptr] != 1)//判断字符ascii值作为下标的位置是否被标记过,是否是重复字符
    			{
    				count++;//当前字符的位置没有被标记过表示没有出现过,则计数+1
    			}
    			table[*ptr++] = 1;;//将字符ascii值作为下标的位置进行标记置1
    		}
    		printf("%d", count);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    💯运行结果:
    二,给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。你可以假设数组是非空的,并且给定的数组总是存在多数元素。

    leetcode【 leetcode 题号:169. 多数元素】【难度:简单】
    示例:
    输入:[3,2,3]
    输出:3
    输入:[2,2,1,1,1,2,2]
    输出:2

    💡分析:

    一个数组中有一个数字出现次数大于 n/2 ,从第 0 个字符开始,假设它就是最多的那个数字,遇到相同的数字则计数 +1 , 遇到不同的则计数 -1 ,其实就是互相消耗,等到计数为 0 的时候,表示本次互拼完毕,从下一个字符重新开始互拼,但是归根结底出现次数大于 n/2 的这个数字数量更多,因此也是最后保留的字符。
    示例: “23335” 首先从字符 2 开始计数 1 ,遇到 3 ,不同则 -1 ,互拼消耗 重新从剩下的 “335” 开始的过程,这时候保存的字符为 3 ,遇到 3 则计数 +1 , 遇到5则计数 -1 ,在计数不为 0 时,走到末尾保存的字符就是个数超过n/2 的字符

    🔑 代码实现
    //多数元素
    int majorityElement(int* nums, int numsSize)
    {
    	int count = 1;
    	int tmp = nums[0];
    	for (int i = 1; i < numsSize; i++)
    	{
    		if (tmp == nums[i]) {//与保存的字符相同则计数+1
    			count++;
    		}
    		else 
    		{//与保存的字符不同则计数-1
    			count--;
    			//计数为0表示有可能保存的字符不是最多的字符,换下一个
    			if (count == 0) tmp = nums[i + 1];
    		}
    	}
    	return tmp;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    💯运行结果:
    三,Lily上课时使用字母数字图片教小朋友们学习英语单词,每次都需要把这些图片按照大小(ASCII码值从小到大)排列收好。请大家给Lily帮忙,通过C语言解决。
    输入描述:Lily使用的图片包括 “A” 到 “Z” 、 “a” 到 “z” 、 “0” 到 “9” 。输入字母或数字个数不超过 1024 。
    输出描述:Lily的所有图片按照从小到大的顺序输出

    OJ链接【牛客网题号: HJ34 图片整理】【难度:中等】
    示例:
    输入:Ihave1nose2hands10fingers
    输出:0112Iaadeeefghhinnnorsssv

    💡分析:

    这道题考察的其实就是字符排序,每个 ascii 字符在内存都有一个对应的 ascii 值,通过内存中数据的存储进行排序就行。
    冒泡排序:相邻数据之间进行比较交换,将较大或较小的数据向后推到数组末尾,然后开始下一轮次大数据的冒泡过程。

    🔑 代码实现
    //HJ34 图片整理
    #include
    int main()
    {
    	char str[1024] = { 0 };
    	while (gets(str))
    	{
    		int len = strlen(str);
    		int i = 0;
    		int j = 0;
    		for (i = 0; i < len; i++)
    		{
    			for (j = 1; j < len - i; j++)
    			{
    				if (str[j] < str[j - 1])
    				{
    					char ch = str[j - 1];
    					str[j - 1] = str[j];
    					str[j] = ch;
    				}
    			}
    		}
    		printf("%s", str);
    	}
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    💯运行结果:
    在这里插入图片描述

    四,给你一个整数数组 nums ,请计算数组的 中心下标 。
    数组中心下标是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
    如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。

    leetcode【 leetcode 题号:724. 寻找数组的中心下标】【难度:简单】
    示例:
    输入:nums = [1, 7, 3, 6, 5, 6]
    输出:3
    解释:
    中心下标是 3 。
    左侧数之和 sum = nums[0] + nums[1] + nums[2] = 1 + 7 + 3 = 11 ,
    右侧数之和 sum = nums[4] + nums[5] = 5 + 6 = 11 ,二者相等。
    输入:nums = [2, 1, -1]
    输出:0
    解释:
    中心下标是 0 。
    左侧数之和 sum = 0 ,(下标 0 左侧不存在元素),
    右侧数之和 sum = nums[1] + nums[2] = 1 + -1 = 0 。

    💡分析:

    给你一个整数数组 ,请计算数组的 中心下标 。nums数组中心下标是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。如果中心下标位于数组最左端,那么左侧数之和视为0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。
    如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 。-1

    🔑 代码实现
    //寻找数组的中心下标
    #include
    int pivotIndex(int* nums, int numsSize)
    {
    	int i = 0;
    	int j = 0;
    	for (i = 0; i < numsSize; i++)//从假设中心点为0开始进行统计判断
    	{
    	//初始化左边之和和右边之和为0
    		int l_num = 0;
    		int r_num = 0;
    		for (j = 0; j < numsSize; j++)
    		{
    			if (i < j)//初始化左边之和和右边之和为0
    			{
    				r_num += nums[j];
    			}
    			else if (i > j)//大于i坐标的都是右边的数字
    			{
    				l_num += nums[j];
    			}
    			if (r_num = l_num)//如果两遍相等则i就是中心坐标
    			{
    				return i;
    			}
    		}
    		return -1;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

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

    OJ链接【 leetcode 题号:747. 至少是其他数字两倍的最大数】【难度:简单】
    示例:
    输入:nums = [3,6,1,0]
    输出:1
    解释:6 是最大的整数,对于数组中的其他整数,6 大于数组中其他元素的两倍。6 的下标是 1 ,所以返回 1 。
    输入:nums = [1,2,3,4]
    输出:-1
    解释:4 没有超过 3 的两倍大,所以返回 -1 。
    输入:nums = [1]
    输出:0
    解释:因为不存在其他数字,所以认为现有数字 1 至少是其他数字的两倍。

    💡分析:

    暴力破解:双重循环遍历数组,对每个元素判断是否是其他元素的两倍。或者先遍历一遍找出最大值,然后遍历一遍判断是否是其他数字二倍。
    更优思想:一次遍历找出最大的数字和次大的数字,判断最大的数字是否是次大数字2倍即可。

    🔑 代码实现
    int dominantIndex(int* nums, int numsSize)
    {
    	if (numsSize == 1) return 0;//特殊情况只有一个元素则特殊处理
    	int max, sec, idx;
    	//先对最大和次大进行选择赋值,注意max和sec不能随意赋初值,因为有可能你赋予的初值就是最大值
    	//因此要使用数组中的数据进行初值赋予。
    	if (nums[0] > nums[1])
    	{
    		max = nums[0];
    		idx = 0;
    		sec = nums[1];
    	}
    	else
    	{
    		max = nums[1];
    		idx = 1;
    		sec = nums[0];
    	}
    	for (int i = 2; i < numsSize; i++)
    	{
    		if (nums[i] > max)
    		{ //当前元素大于max,则意味着要替换
    			sec = max; //先将原先最大的保存到sec中,则他就是次大的
    			max = nums[i]; //再将最大的放到max中
    			idx = i; //保存max值的下标
    		}
    		else if (nums[i] > sec)
    		{
    			//避免刚好nums[0]就是最大的情况,因为不切换最大而导致次大无法判断情况
    			sec = nums[i];
    		}
    	}
    	if (max >= sec * 2)
    	{
    		return idx;
    	}
    	return -1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    六,给定两个数组,编写一个函数来计算它们的交集。

    OJ链接【 leetcode 题号:349. 两个数组的交集】【难度:简单】
    示例:
    输入:nums1 = [1,2,2,1], nums2 = [2,2]
    输出:[2]
    输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
    输出:[9,4]

    💡分析:

    暴力破解即可,将 nums1 数组中的每一个数字,判断是否存在于 nums2 数组中,通过这种方式找出交集数据,找出之后判断这个数组是否已经在返回数组中存在,不存在则添加到返回数组中即可。

    🔑 代码实现
    int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize)
    {
    	static int arr[1000];
    	*returnSize = 0;
    	int i, j;
    	for (i = 0; i < nums1Size; i++)
    	{
    		for (j = 0; j < nums2Size; j++) 
    		{
    			if (nums2[j] == nums1[i]) 
    				break;//判断nums1[i] 是否在nums2数组中
    		}
    		if (j == nums2Size) 
    		{// nums1中i位置的数据在nums2数组中不存在,则非交集数据
    			continue;
    		}
    		//只有在另一个数组中存在的数据才能走下来,判断是否已经被添加到返回数组中
    		for (j = 0; j < *returnSize; j++) 
    		{
    			if (nums1[i] == arr[j]) break;//判断nums1[i] 是否在 arr 这个返回数组中
    		}
    		if (j == *returnSize)
    		{//不在返回数组中,则添加到返回数组中
    			arr[*returnSize] = nums1[i];
    			*returnSize += 1;
    		}
    	}
    	return arr;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    七,给定一个长度为 n 的非降序数组和一个非负数整数 k ,要求统计 k 在数组中出现的次数
    数据范围: 0≤n≤1000 , 0≤k≤100 ,数组中每个元素的值满足 0≤val≤100

    OJ链接【牛客网题号: JZ53 数字在升序数组中出现的次数】【难度:简单】
    示例:
    输入:[1,2,3,3,3,3,4,5],3
    返回值:4

    💡分析:

    采用遍历也能搞定,不过数组为非降序,采用二分查找的思想最优,先二分找到最左边的数字位置,再二分查找最右边的数字位置,两个位置相减+1就是长度了
    中间比找的值大:则要找的数字肯定在右边, left = mid + 1;
    中间比找的值小:则要找的数字肯定在左边, right = mid - 1;
    中间值与找的值相同:
    找的最左边数字:如果mid就是left,则返回mid就行,否则重置right=mid-1,把中心不断向左偏移
    找的最右边数字:如果mid就是right,则返回mid就行,否则重置left=mid+1,把中心不断向右偏移

    🔑 代码实现
    #include
    int get_last_or_first_idx(int* data, int len, int k, int flag) 
    {//flag:0-找左边, 1-找右边
    	int left = 0, right = len - 1, mid;
    	while (left <= right)
    	{
    		mid = left + (right - left) / 2;
    		if (data[mid] > k)
    			right = mid - 1;
    		else if (data[mid] < k)
    			left = mid + 1;
    		else {
    			if (flag == 0) 
    			{//flag==0时,找最左边的数字
    				if (mid == left || data[mid - 1] != k)
    					return mid;
    				else right = mid - 1;//把中心向左推
    			}
    			else
    			{//flag==1时,找最右边的数字
    				if (mid == right || data[mid + 1] != k)
    					return mid;
    				else left = mid + 1;//把中心向右推
    			}
    		}
    	}
    	return -1;
    }
    int GetNumberOfK(int* data, int dataLen, int k)
    {
    	if (dataLen == 0) return 0;
    	int left = get_last_or_first_idx(data, dataLen, k, 0);
    	int right = get_last_or_first_idx(data, dataLen, k, 1);
    	if (left == -1 && right == -1) return 0; //表示没有找到k这个数据
    	return right - left + 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    八,整数转换。编写一个函数,确定需要改变几个位才能将整数 A 转成整数 B 。

    OJ链接【 leetcode 题号:面试题 05.06. 整数转换】【难度:简单】
    示例:
    输入:A = 29 (或者0b11101), B = 15(或者0b01111) 输入:A = 1,B = 2
    输出:2 输出:2

    💡分析:

    其实问需要修改多少个比特位,问的就是有多少个比特位不同而已,因为有多少位不同就修改多少位。

    🔑 代码实现
    int get_bin_count(int num)
    {
    	int count = 0;
    	for (int i = 0; i < 32; i++)
    	{
    		if ((num >> i) & 1)
    			count++;
    	}
    	return count;
    }
    int convertInteger(int A, int B)
    {
    	return get_bin_count(A ^ B);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    💘后期会推出更多C语言练习题,希望大家与我共同进步,早日成为大佬!

  • 相关阅读:
    mysql面试题34:Hash索引和B+树区别是什么?在设计索引怎么选择?
    58 练习 1
    Mybatis-Plus 快速入门
    lego-loam 跑 kitti00包(kitti2bag+lego-loam+evo)详细版
    不懂 Kubernetes 实现云原生是什么体验?
    【C语言从入门到入土】第二章初识
    Mysql 执行 sql 文件导入数据时报错: Got a packet bigger than ‘max_allowed_packet‘ bytes
    HBase之BlockCache
    C语言基础知识 -- 指针
    KD tree-基于树的ANN近邻搜索
  • 原文地址:https://blog.csdn.net/2201_75642960/article/details/132515944