1.输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数
比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999
int* printNumbers(int n, int* returnSize )
{
*returnSize = pow(10, n) - 1; //确定最大的数字
int *arr = (int *)malloc(sizeof(int)*(*returnSize)); //申请足够大小的空间
for (int i = 0; i < *returnSize; i++)
{
arr[i] = i+1; //下标从0开始,而数值从1开始
}
return arr;
}
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型 最大位数
* @return int整型一维数组
* @return int* returnSize 返回数组行数
*
* C语言声明定义全局变量请加上static,防止重复定义
*/
static int arr[100001];
int* printNumbers(int n, int* returnSize ) {
int max=1;
for(int i=0;i<n;i++)
{
max*=10;
}
int i=0;
for(i=0;i<max;i++)
{
arr[i-1]=i;
}
*returnSize=i-1;
return arr;
}
2.根据输入的日期,计算是这一年的第几天
#include <stdio.h>
int isleapyear(int year)
{
if(0 == year%4)
{
if(0 == year%100 && 0 != year%400)
return 0;
else
return 1;
}
else
return 0;
}
int main()
{
int daynum_of_leapyear[12] = {31,29,31,30,31,30,31,31,30,31,30,31};
int daynum_of_commonyear[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
int year,month,day;
scanf("%d", &year);
scanf("%d", &month);
scanf("%d", &day);
int daynum = 0;
if(1 == isleapyear(year))
{
for(int i =0; i<month-1; i++)
{
daynum += daynum_of_leapyear[i];
}
}
else
{
for(int i =0; i<month-1; i++)
{
daynum += daynum_of_commonyear[i];
}
}
daynum += day;
printf("%d",daynum);
return 0;
}
3.求输出结果
#include <stdio.h>
#define N 2
#define M N + 1
#define NUM (M + 1) * M / 2
int main()
{
printf("%d\n", NUM);
return 0;
}
宏只是替换,替换后NUM的样子是(2+1+1)*2+1/2,计算得8
#include<stdio.h>
int main()
{
char s[] = "\\123456\123456\t";
printf("%d\n", strlen(s));
return 0;
}
注意:\\ 表示字符'\',\123表示字符'{',\t表示制表符,这些都是一个字符
结果是12
下面3段程序代码的效果一样吗
int b;
(1)const int *a = &b;
(2)int const *a = &b;
(3)int *const a = &b;
const在*的左边,则指针指向的变量的值不可直接通过指针改变(可以通过其他途径改变);在*的右边,则指针的指向不可变。简记为"左定值,右定向",(1)和(2)const都在*的左边,(3)中const在*的右边,
(1)=(2)
#include <stdio.h>
int i;
void prt()
{
for (i = 5; i < 8; i++)
printf("%c", '*');
printf("\t");
}
int main()
{
for (i = 5; i <= 8; i++)
prt();
return 0;
}
全局变量i,在main()中修改为5,第一次在prt()中执行循环输出三次'*',i被修改为8,回到main()中第二次调用prt()时,i<8为假,循环结束没输出,执行一次print("\t"),再次回到主函数后i++变为9,i<=8为假,循环结束;
***
int main()
{
int a=3;
printf("%d\n",(a+=a-=a*a));
return 0;
}
a+=a-=a*a等价于a=a+(a=a-a*a),即先计算a=a-a*a,所以此时a的值为3-3*3=-6,再计算-6+(-6)=-12赋值给a,所以a的值为-12,也就是整个表达式的值,
12
#include <stdio.h>
int main()
{
char c;
int v0=0,v1=0,v2=0;
do
{
switch(c=getchar())
{
case'a':case'A':
case'e':case'E':
case'i':case'I':
case'o':case'O':
case'u':case'U':v1 += 1;
default:v0+= 1;v2+=1;
}
}while(c!='\n');
printf("v0=%d,v1=%d,v2=%d\n",v0,v1,v2);
return 0;
}
从键盘输入 ADescriptor<回车> ,则程序的运行结果是v0=12,v1=4,v2=12
代码switch语句中没有break,则每次找到入口进入后,顺序执行到代码块结束为止。例如当c为'A'时,从case 'A'进入,先后执行v1+=1;v0+=1;v2+=1;,而当c为'p'时,从default进入,先后执行v0+=1;v2+=1;,容易看出最终v0和v2是相等的
#include <stdio.h>
int main()
{
char ch;
while ((ch = getchar()) != '\n')
{
if (ch % 2 != 0 && (ch >= 'a' && ch <= 'z'))
ch = ch - 'a' + 'A';
putchar(ch);
}
printf("\n");
return 0;
}
输入1abcedf2df<回车> ,输出结果1AbCEdf2df
程序首先考虑ch的ASCII码值是不是奇数,再看是不是小写字母,同时满足时被改为大写字母
4.验证尼科彻斯定理
即:任何一个整数 m 的立方都可以写成 m 个连续奇数之和
1^3=1
2^3=3+5
3^3=7+9+11
4^3=13+15+17+19
#include <stdio.h>
int main()
{
int m;
while(~scanf("%d",&m))
{
int i,n=m*(m-1)+1;
for(i=1;i<=m;i++)
{
printf("%d",n);
n+=2;
if(i!=m)
{
printf("+");
}
}
printf("\n");
}
}
#include "stdio.h"
#include "string.h"
int main()
{
int m;
while (scanf("%d", &m) != EOF)
{
//long sum = m*m*m;
int start = m*m - m + 1;;
int i = 0;
/*if (m%2 == 0)
{
start = m*m - m + 1;
}
else
{
start = m*m - 2*(m/2);
}*/
while (m > 1)
{
printf("%d+", start+2*i);
i++;
m--;
}
printf("%d\n", start+2*i);
}
return 0;
}
5.求等差数列前n项和
等差数列 2,5,8,11,14。。。。
#include <stdio.h>
int main(void)
{
int num;
while(scanf("%d", &num)!=EOF)
printf("%d\n", ((4+3*(num-1))*num)>>1);
return 0;
}
6.求平均数和负数的个数
首先输入要输入的整数个数n,然后输入n个整数。输出为n个整数中负数的个数,和所有正整数的平均值,结果保留一位小数。0即不是正整数,也不是负数,不计入计算
#include <stdio.h>
int main()
{
int n;
while(scanf("%d",&n) != EOF)
{
int cnt1 = 0;
int cnt2 = 0;
int sum = 0;
int num;
double result;
for(int i = 0;i < n;i++)
{
scanf("%d",&num);
if(num < 0)
{
cnt1++;
}
else if(num > 0)
{
sum += num;
cnt2++;
}
}
result =(float) sum / cnt2;
printf("%d %0.1lf\n",cnt1,result);
}
return 0;
}
7.旋转数组的最小数字
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
数据范围:1 \le n \le 100001≤n≤10000,数组中任意元素的值: 0 \le val \le 100000≤val≤10000
/**
*
* @param rotateArray int整型一维数组
* @param rotateArrayLen int rotateArray数组长度
* @return int整型
*/
int minNumberInRotateArray(int* rotateArray, int rotateArrayLen ) {
// write code here
if (0 == rotateArrayLen)
{
return 0;
}
int mid = 0, start = 0, end = 0;
end = rotateArrayLen - 1;
if (rotateArray[start] < rotateArray[end])
{
return rotateArray[start];
}
while (start < end)
{
mid = start + (end - start) / 2;
if (rotateArray[mid] > rotateArray[end])
{// 最小元素在右半侧
start = mid + 1;
}
else if (rotateArray[mid] == rotateArray[end])
{
end = end - 1;
}
else
{// 最小元素在左半侧
end = mid;
}
}
return rotateArray[start];
}
/**
*
* @param rotateArray int整型一维数组
* @param rotateArrayLen int rotateArray数组长度
* @return int整型
*/
int minNumberInRotateArray(int* rotateArray, int rotateArrayLen )
{
int l = 0;
int r = rotateArrayLen - 1;
int middle;
while (l < r)
{
middle = (l + r) / 2;
if (rotateArray[r] < rotateArray[middle])
{
l = middle + 1;
}
else if (rotateArray[r] > rotateArray[middle])
{
r = middle;
}
else
{
r--;
}
}
return rotateArray[l];
}
8.对数组a进行插入排序(升序)
int a[] = {4, 0, 2, 3, 1}, i, j, t;
for(i = 1;i < 5;i++)
{
t = a[i];
j = i - 1;
while(j >= 0 && t < a[j])
{
a[j + 1] = a[j];
--j;
}
a[j + 1] = t;
}
这是一个升序插入排序算法,读完即懂,第i次排序时,t=a[i]作为临时变量保存这一次待插入值,j=i-1故而while循环中j是从下标i的前一项开始向下标0遍历,判断t<a[j]为真a[j+1]=a[j],j+1在遍历之初是等于i的,也就是将下标i位置用前边较大的值覆盖,依次把前边的元素后移,直到a[j]不大于t的时候将t插入到下标j+1位置,使得前i个元素达到有序,方便第i+1次排序操作,所以第i次排序时前边i-1个元素都是有序的。
9.找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回
集合 s 包含从 1 到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且有一个数字重复 。
给定一个数组 nums 代表了集合 S 发生错误后的结果。
int* findErrorNums(int* nums, int numsSize, int* returnSize)
{
int* a = (int*)malloc(sizeof(int)*(numsSize));
for(int i = 0; i < numsSize; i++)
{ // 初始化数组
a[i] = 0;
}
for(int i = 0; i < numsSize; i++)
{ // 关键:记录各个数字出现的频次
a[nums[i]-1]++;
}
int* res = (int*)malloc(sizeof(int)*2);
for(int i = 0; i < numsSize; i++)
{
if(a[i] == 2)
{
res[0] = i+1;
}
if(a[i] == 0)
{
res[1] = i+1;
}
}
*returnSize = 2;
return res;
}
int* findErrorNums(int* nums, int numsSize, int* returnSize)
{
*returnSize = 2;
//遍历nums数组,将其中数据对应的位置1, 哪一位如果已经重置过则意味着数据重复了
int *arr = (int *)calloc(numsSize + 1, sizeof(int));//申请numsSize个整形空间,并初始化为0
int *ret = (int *)calloc(*returnSize, sizeof(int)); //申请2个整形空间,并初始化为0
int cur_sum = 0, old_sum = 0;
for (int i = 0; i < numsSize; i++)
{
if (arr[nums[i]] == 1)
{ //这个数字在上边数组的对应位置已经置过1了,则重复。
ret[0] = nums[i];//找到重复的数字
}
arr[nums[i]] = 1; //将标记数组的对应数据位置1
old_sum += i + 1; // 1~n的求和
cur_sum += nums[i]; //当前数组中的数据求和(多了一个重复的,少了一个丢失的)
}
ret[1] = old_sum - (cur_sum - ret[0]);//原始总和,减去去掉重复后的当前总和就是丢失的数字
free(arr);
return ret;
}
10.密码检查
小明同学最近开发了一个网站,在用户注册账户的时候,需要设置账户的密码,为了加强账户的安全性,小明对密码强度有一定要求:
1. 密码只能由大写字母,小写字母,数字构成;
2. 密码不能以数字开头;
3. 密码中至少出现大写字母,小写字母和数字这三种字符类型中的两种;
4. 密码长度至少为8
现在小明受到了n个密码,他想请你写程序判断这些密码中哪些是合适的,哪些是不合法的。
输入描述:
输入一个数n,接下来有n(n≤100)行,每行一个字符串,表示一个密码,输入保证字符串中只出现大写字母,小写字母和数字,字符串长度不超过100。
输出描述:
输入n行,如果密码合法,输出YES,不合法输出NO
#include<stdio.h>
#include<ctype.h>
#include<string.h>
int main(void)
{
int n,count=0;
char s[100];
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
int count1 = 0, count2 = 0, count3 = 0;
scanf("%s", &s);
if (strlen(s) < 8)
{
printf("NO\n");
continue;
}
if (isdigit(s[0]) != 0)
{
printf("NO\n");
continue;
}
int j = 0;
while (s[j] != '\0')
{
if (isupper(s[j]) != 0)
count1 = 4;
else if (islower(s[j]) != 0)
count2 = 2;
else if (isdigit(s[j]) != 0)
count3 = 1;
else
{
count1 = 0, count2 = 0, count3 = 0;
break;
}
j++;
}
count = count1 + count2 + count3;
if (count == 7 || count == 3 || count == 5 || count == 6)
printf("YES\n");
else
printf("NO\n");
}
}
#include<stdio.h>
#include<ctype.h>
#include<string.h>
int main(void)
{
int n,count=0;
char s[100];
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
int count1 = 0, count2 = 0, count3 = 0;
scanf("%s", &s);
if (strlen(s) < 8)
{
printf("NO\n");
continue;
}
if (isdigit(s[0]) != 0)
{
printf("NO\n");
continue;
}
int j = 0;
while (s[j] != '\0')
{
if (isupper(s[j]) != 0)
count1 = 4;
else if (islower(s[j]) != 0)
count2 = 2;
else if (isdigit(s[j]) != 0)
count3 = 1;
else
{
count1 = 0, count2 = 0, count3 = 0;
break;
}
j++;
}
count = count1 + count2 + count3;
if (count == 7 || count == 3 || count == 5 || count == 6)
printf("YES\n");
else
printf("NO\n");
}
}
11.将字符数组ch中的大写字母转换成小写
#include <stdio.h>
int main()
{
char ch[80] = "123abcdEFG*&";
int j;
puts(ch);
for(j = 0; ch[j] != '\0'; j++)
if(ch[j] >= 'A' && ch[j] <= 'Z')
ch[j] = ch[j] + 'e' - 'E';
puts(ch);
return 0;
}
12.数字在升序数组中出现的次数
给定一个长度为 n 的非降序数组和一个非负数整数 k ,要求统计 k 在数组中出现的次数。
数据范围:0 \le n \le 1000 , 0 \le k \le 1000≤n≤1000,0≤k≤100,数组中每个元素的值满足 0 \le val \le 1000≤val≤100
/**
*
* @param data int整型一维数组
* @param dataLen int data数组长度
* @param k int整型
* @return int整型
*/
int GetNumberOfK(int* data, int dataLen, int k )
{
// write code here
//这种有序还是数组就要用二分法,比直接遍历能节省一半时间
if(dataLen==0)return 0;
int i,j,right=0,left=0,m;
i=0;
j=dataLen-1;
while(i<=j)
{
m=(i+j)/2;
if(k>=data[m])
i=m+1;
else
j=m-1;
}
right=i;//i,j需要重新赋值!因为需要再来一次二次查找
i=0;
j=dataLen-1;
while(i<=j)
{
m=(i+j)/2;
if(k>data[m])
i=m+1;
else
j=m-1;
}
left=j;
return right-left-1;
}
/**
*
* @param data int整型一维数组
* @param dataLen int data数组长度
* @param k int整型
* @return int整型
*/
int GetNumberOfK(int* data, int dataLen, int k )
{
int i=0;
int ret=0;
for(i=0;i<dataLen;i++)
{
if(data[i]==k)
{
ret++;
}
}
return ret;// write code here
}
采用遍历也能搞定,不过数组为非降序,采用二分查找的思想最优,先二分找到最左边的数字位置,再二分查找最右边的数字位置,两个位置相减+1就是长度了
中间比找的值大:则要找的数字肯定在右边, left = mid + 1;
中间比找的值小:则要找的数字肯定在左边, right = mid - 1;
中间值与找的值相同:
找的最左边数字:如果mid就是left,则返回mid就行,否则重置right=mid-1,把中心不断向左偏移
找的最右边数字:如果mid就是right,则返回mid就行,否则重置left=mid+1,把中心不断向右偏移
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;
}
13.整数转换
编写一个函数,确定需要改变几个位才能将整数A转成整数B
输入:A = 29 (或者0b11101), B = 15(或者0b01111) 输出:2
其实问需要修改多少个比特位,问的就是有多少个比特位不同而已,因为有多少位不同就修改多少位。
int convertInteger(int A, int B)
{
A^=B;
int ret=0;
for(int i=0;i<32;i++)
{
if((A>>i)&1==1)
{
ret++;
}
}
return ret;
}
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);
}
14.至少是其他数字两倍的最大数
给你一个整数数组nums,其中总是存在唯一的一个最大整数 。请你找出数组中的最大元素并检查它是否 至少是数组中每个其他数字的两倍 。如果是,则返回 最大元素的下标 ,否则返回 -1 。
示例:
输入:nums = [3,6,1,0]
输出:1
解释:6 是最大的整数,对于数组中的其他整数,6 大于数组中其他元素的两倍。6 的下标是 1 ,所以返回 1 。输入:nums = [1,2,3,4]
输出:-1
解释:4 没有超过 3 的两倍大,所以返回 -1 。输入:nums = [1]
输出:0
解释:因为不存在其他数字,所以认为现有数字 1 至少是其他数字的两倍。
int dominantIndex(int *nums, int numsSize)
{
if (numsSize == 1)
return 0; // 如果只有一a个数字,题目中满足条件,所以返回下标0
int max = 0; // 已知所有int都大于等于0
int second = 0;
int index = 0; // 用index储存最大值的下标
for (int i = 0; i < numsSize; i++)
{
if (nums[i] > max)
{
second = max; // 原来最大值更新为次大值
max = nums[i]; // 更新最大值
index = i; // 更新最大值下标
}
else if (nums[i] > second) // 但小于max
{
second = nums[i]; // 更新次大值
}
}
return (max >= (2 * second)) ? index : -1;
}
int dominantIndex(int *nums, int numsSize)
{
if (numsSize == 1)
return 0;
int max = INT_MIN; // 如果题目中没有说明所有int都大于等于0
int second = INT_MIN; // 如果题目中没有说明所有int都大于等于0
int index = 0;
for (int i = 0; i < numsSize; i++)
// 由于max和second分别初始化为INT_MIN,因此遍历i可以从0开始
{
if (nums[i] > max)
{
second = max;
max = nums[i];
index = i;
}
else if (nums[i] > second)
{
second = nums[i];
}
}
return (max >= (2 * second)) ? index : -1;
}
如果max初始值为数组第一个数,那么遍历时必须从第二个数开始(i=1)
原因是:如果第一个数是全数组最大的数,那么如果从i=0开始遍历,second将永远也是最大数,所以返回将永远是-1,无法通过case
int dominantIndex(int *nums, int numsSize)
{
if (numsSize == 1)
return 0;
int max = nums[0]; // 如果max初始值为数组第一个数
int second = INT_MIN;
int index = 0;
for (int i = 1; i < numsSize; i++) // 必须从i=1开始遍历。
{
if (nums[i] > max)
{
second = max;
max = nums[i];
index = i;
}
else if (nums[i] > second)
{
second = nums[i];
}
}
return (max >= (2 * second)) ? index : -1;
}
15.给定两个数组,编写一个函数来计算它们的交集
方法一:两个集合
计算两个数组的交集,直观的方法是遍历数组 nums1,对于其中的每个元素,遍历数组 nums2 判断该元素是否在数组 nums2 中,如果存在,则将该元素添加到返回值。假设数组 nums1 和 nums2 的长度分别是 mm 和 nn,则遍历数组 nums1 需要 O(m)O(m) 的时间,判断 nums1 中的每个元素是否在数组 nums2 中需要 O(n)O(n) 的时间,因此总时间复杂度是 O(mn)O(mn)。
如果使用哈希集合存储元素,则可以在 O(1)O(1) 的时间内判断一个元素是否在集合中,从而降低时间复杂度。
首先使用两个集合分别存储两个数组中的元素,然后遍历较小的集合,判断其中的每个元素是否在另一个集合中,如果元素也在另一个集合中,则将该元素添加到返回值。该方法的时间复杂度可以降低到 O(m+n)O(m+n)。
struct unordered_set
{
int key;
UT_hash_handle hh;
};
struct unordered_set* find(struct unordered_set** hashtable, int ikey)
{
struct unordered_set* tmp;
HASH_FIND_INT(*hashtable, &ikey, tmp);
return tmp;
}
void insert(struct unordered_set** hashtable, int ikey)
{
struct unordered_set* tmp = find(hashtable, ikey);
if (tmp != NULL) return;
tmp = malloc(sizeof(struct unordered_set));
tmp->key = ikey;
HASH_ADD_INT(*hashtable, key, tmp);
}
int* getIntersection(struct unordered_set** set1, struct unordered_set** set2, int* returnSize)
{
if (HASH_COUNT(*set1) > HASH_COUNT(*set2))
{
return getIntersection(set2, set1, returnSize);
}
int* intersection = malloc(sizeof(int) * (HASH_COUNT(*set1) + HASH_COUNT(*set2)));
struct unordered_set *s, *tmp;
HASH_ITER(hh, *set1, s, tmp)
{
if (find(set2, s->key))
{
intersection[(*returnSize)++] = s->key;
}
}
return intersection;
}
int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize) {
*returnSize = 0;
struct unordered_set *set1 = NULL, *set2 = NULL;
for (int i = 0; i < nums1Size; i++)
{
insert(&set1, nums1[i]);
}
for (int i = 0; i < nums2Size; i++)
{
insert(&set2, nums2[i]);
}
return getIntersection(&set1, &set2, returnSize);
}
方法二:排序 + 双指针
如果两个数组是有序的,则可以使用双指针的方法得到两个数组的交集。
首先对两个数组进行排序,然后使用两个指针遍历两个数组。可以预见的是加入答案的数组的元素一定是递增的,为了保证加入元素的唯一性,我们需要额外记录变量 \textit{pre}pre 表示上一次加入答案数组的元素。
初始时,两个指针分别指向两个数组的头部。每次比较两个指针指向的两个数组中的数字,如果两个数字不相等,则将指向较小数字的指针右移一位,如果两个数字相等,且该数字不等于 \textit{pre}pre ,将该数字添加到答案并更新 \textit{pre}pre 变量,同时将两个指针都右移一位。当至少有一个指针超出数组范围时,遍历结束。
int cmp(void* a, void* b)
{
return *(int*)a - *(int*)b;
}
int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize) {
qsort(nums1, nums1Size, sizeof(int), cmp);
qsort(nums2, nums2Size, sizeof(int), cmp);
*returnSize = 0;
int index1 = 0, index2 = 0;
int* intersection = malloc(sizeof(int) * (nums1Size + nums2Size));
while (index1 < nums1Size && index2 < nums2Size)
{
int num1 = nums1[index1], num2 = nums2[index2];
if (num1 == num2) {
// 保证加入元素的唯一性
if (!(*returnSize) || num1 != intersection[(*returnSize) - 1])
{
intersection[(*returnSize)++] = num1;
}
index1++;
index2++;
}
else if (num1 < num2)
{
index1++;
}
else
{
index2++;
}
}
return intersection;
}
int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize)
{
static int arr[1000];
*returnSize = 0;
int i, j, k;
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;
}
16.求下面程序的输出
代码实现了递归倒序打印字符串的功能,但是++s使得s的值发生了变化,回不到'G'的位置上,故而没有打印'G'
int main()
{
char str[] = "Geneius";
print(str);
return 0;
}
print(char *s)
{
if(*s)
{
print(++s);
printf("%c", *s);
}
}
输出结果:suiene
#include<stdio.h>
int main()
{
int a [12]= {1,2,3,4,5,6,7,8,9,10,11,12},*p[4],i;
for(i=0;i<4;i++)
p[i]=&a [i*3];
printf("%d\n",p[3][2]);
return 0;
}
p是一个指针数组,p[i] = &a[i*3]相当于是把数组a每3个一组分开并把每组的首地址存在p数组,此时p类似一个4行3列的
二维数组,p[3][2]就是4行第3个元素12
输出结果是12
int main()
{
char a = 'a',b;
printf("%c,", ++a);
printf("%c\n", b = a++);
return 0;
}
输出结果是:b b
变量a里边存的是字符'a',第一次输出先加加再输出,输出的是'b';第二次输出的时候,a先赋值再加加,赋值给b的就是a原来的值,输出b的时候的还是'b'
int func(int x)
{
int count = 0;
while (x)
{
count++;
x = x&(x - 1);//与运算
}
return count;
}
传入 -1 ,则在64位机器上函数返回32
x=x&(x-1)这个表达式执行一次就会将x的2进制中最右边的1去掉,在x变成0之前,表达式能执行几次,就去掉几个1,所以这个代码实现了求一个有符号整数二进制补码中1的个数的功能,我们知道-1的补码是全1,而int类型4个字节32位
int count = 0;
int x = -1;
while(x)
{
count++;
x = x >> 1;
}
printf("%d",count);
有符号数右移运算高位是补符号位的,负数的符号位是1,所以x永远不会变为0,是个死循环
死循环没结果
int main()
{
int a=1,b=2,m=0,n=0,k;
k=(n=b<a)&&(m=a);
printf("%d,%d\n",k,m);
return 0;
}
k=(n=b<a)&&(m=a);这部分的执行顺序如下:先执行n=b<a部分,其中,关系运算符优先级高于赋值运算符,所以先算b<a,得到0,n=0赋值运算的结果将作为括号内表达式的结果,即(n=b<a)&&(m=a)转换成(0)&&(m=a),&&运算前表达式为假,则后面的括号(m=a)不运算,m值还是0,最后,&&的结果是0,即k=0
输出结果是:0 0
#include <stdio.h>
int main()
{
int x = -1;
unsigned int y = 2;
if (x > y)
{
printf("x is greater");
}
else
{
printf("y is greater");
}
return 0;
}
输出结果是:x is greater
x是有符号数-1,内存中是全1,当有符号的x和无符号数进行比较时,x会隐式类型转换被当做无符号数,是一个很大的数,这时就选择A了。
void func()
{
int k = 1^(1 << 31 >> 31);
printf("%d\n", k);
}
(1 << 31 );左移31位,并在右侧填充0,得到0x80000000,即符号位为1,其他为0,即-2147483648
int k = 1^(1 << 31 >> 31);注意,这里在右移的时候,符号位保持为1,右移后填充1,结果为0xFFFFFFFF,即-1,
0x00000001^0xFFFFFFFF,即0xFFFFFFFE(-2)
输出结果是 -2
#include <stdio.h>
int main()
{
int i = 1;
sizeof(i++);
printf("%d\n", i);
return 0;
}
一般表达式的运算是在运行时执行的,而sizeof是一个编译阶段就执行的运算符,在其内的任何运算都不执行,只推测出其中表达式结果的类型求其大小,故前后i的值不变。
输出结果是:1
int main()
{
char c='A';
if('0'<=c<='9')
printf("YES");
else
printf("NO");
return 0;
}
'0'<=c<='9'并非判断x大于等于字符0,小于等于字符9,而是先执行'0'<=c,使用这个表达式的结果再和'9'比较,'0'的ASCII码值是48,'A'的ASCII码值是'65',故'0'<c是真值1,1无疑是小于字符'9'的,最终是真。
输出结果是:YES
#include<stdio.h>
int main()
{
int n = 1001;
int ans = 0;
for(int i = 1; i <= n; ++i)
{
ans ^= i % 3;
}
printf("%d",ans);
return 0;
}
i % 3 的值按1、2、0循环,可推算出ans按1、3、3、2、0、0循环,循环进行1001次,而1001%6=5,也就是ans按规律得到的第5个数为最终结果,故ans=0
int fun(unsigned int x)
{
int n = 0;
while(x + 1)
{
n++;
x = x | (x + 1);
}
return n;
}
x=2014 ,函数的返回值是23。
这个作用是对整型中0的个数进行统计,x=x|(x+1);的作用是每次循环把x的二进制中从右往左数的最后一位0变成1,直道变成全1的时候x+1就溢出为全0,循环结束。2014的二进制是0000 0000 000 0000 0000 0111 1101 1110,所以结果是23
int fun(char *s)
{
char *t = s;
while(*t++);
return(t-s);
}
该函数的功能是计算s所指字符串占用内存字节的个数
循环在*t为0时停止,同时t++,t最后会停在字符串结束的'\0'之后的一个位置,t作为尾部指针减去头部指针就是整个字符串占用内存的字节数,包含\0在内;而c答案字符串长度不包括最后的\0
#include <stdio.h>
int main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, *p = a + 5, *q = NULL;
*q = *(p+5);
printf("%d %d\n", *p, *q);
return 0;
}
指针q初始化为NULL,接着又解引用指针q,是错误的,对NULL指针是不能解引用的。
输出结果是:运行后报错
float f[10];
// 假设这里有对f进行初始化的代码
for(int i = 0; i < 10;)
{
if(f[++i] == 0)
break;
}
指出代码的缺陷:f是float型数据直接做相等判断有风险 f[++i]应该是f[i++]
一般float型只能精确到小数后六位(即1e-6),将float型数据的绝对值与1e-6比较,来判断是否相等(为零)。float的精度误差在1e-6;double精度误差在1e-15;所以要判断一个float型数:if(fabs(f)<1e-6);要判断一个double型数:if(fabs(f)<1e-15);若满足,则为零。考虑B选项是对的。若要判断float a,b是否相等,要看if(fabs(a-b)<1e-6)是否为真。C选项,考虑的是数组越界问题。
void GetMemory(char **p, int num)
{
if(NULL == p && num <= 0)//1
return;
*p = (char*)malloc(num);
return;
}
int main()
{
char *str = NULL;
GetMemory(&str, 80); //2
if(NULL != str)
{
strcpy(&str, "hello"); //3
printf(str); //4
}
return 0;
}
指出程序的错误:1和3
第1处两种情况之一成立都是要返回的,应该用或,此处用与错误。在语句GetMemory(&str,100);中传入str的地址,在语句char*str=NULL;中str初始化为空指针,但是str指针变量也有地址,所以参数char**p里面的p保存的是指针变量str的地址,所以调用GetMemory函数之后,动态开辟的空间的地址存放在了str中,在函数返回之后没有释放内存,但是这不会导致程序错误,只会导致内存泄漏。第3处用&str是错的,应该直接用str,是刚申请下来的空间首地址,可以用来接收字符串的copy。
#include <stdio.h>
typedef union
{
int a;
struct
{
short b;
short c;
};
}X;
int main()
{
X x;
x.a = 0x20150810;
printf("%x,%x\n", x.b, x.c);
return 0;
}
代码的输出结果有可能是哪些 2015,810 810,2015
对于0x20150810
如果按照大端模式存储:从低地址到高地址:20 15 08 10 输出从低地址到高地址:20 15 08 10
如果按照小端模式存储:从低地址到高地址:10 08 15 20 输出从高地址到低地址:08 10 20 15
此数以int类型赋值给联合体x.a,而以结构成员b和c分开访问,分别拿到低地址的2个字节和高地址的2个字节,大端下是2015和810,小端下是810和2015
#define MAX 255
int main()
{
unsigned char A[MAX], i;
for(i = 0; i <= MAX; i++)
A[i] = i;
return 0;
}
程序执行后会有什么错误或者效果:数组越界 死循环
数组下标越界:数组大小255,但是当a[255]就是256个元素,导致越界了。死循环:这个是因为无符号字符型的变量大小在0-255之间,所以说i永远不可能大于255的,是个死循环。内存泄漏:创建的临时变量,在栈中,应该会由系统自动释放,所以应该是不存在内存泄漏的问题。栈溢出:属于缓冲区溢出的一种。栈溢出是由于C语言系列没有内置检查机制来确保复制到缓冲区的数据不得大于缓冲区的大小,因此当这个数据足够大的时候,将会溢出缓冲区的范围。
#include<stdio.h>
int main()
{
unsigned char i = 7;
int j = 0;
for(;i > 0;i -= 3)
{
++j;
}
printf("%d\n", j);
return 0;
}
程序的输出是:173
17.图片整理
Lily上课时使用字母数字图片教小朋友们学习英语单词,每次都需要把这些图片按照大小(ASCII码值从小到大)排列收好。
数据范围:每组输入的字符串长度满足 1 \le n \le 1000 \1≤n≤1000
输入描述:
Lily使用的图片包括"A"到"Z"、"a"到"z"、"0"到"9"。输入字母或数字个数不超过1024。
输出描述:
Lily的所有图片按照从小到大的顺序输出
输入:Ihave1nose2hands10fingers
输出:0112Iaadeeefghhinnnorsssv
#include<stdio.h>#include<string.h>#include<stdlib.h>
int cmp(void*e1,void*e2)
{
if(*(char*)e1>*(char*)e2)return 1;
else if(*(char*)e1<*(char*)e2)return -1;
return 0;
}
int main()
{
char a[1010];
while(~scanf("%s",a))
{
int sz=strlen(a);
qsort(a,sz,1,cmp);
printf("%s\n",a);
}
return 0;
}
#include <stdio.h>
const int MAX = 1024;
int getIndex(char arr[], int left, int right)
{
int pivot = arr[left];
while (left < right)
{
// 从右往左
while (left < right && arr[right] >= pivot)
right--;
arr[left] = arr[right];
// 从左往右
while (left < right && arr[left] <= pivot)
left++;
arr[right] = arr[left];
}
arr[left] = pivot;
return left;
}
void qSort(char arr[], int left, int right)
{
if (left < right)
{
int index = getIndex(arr, left, right);
qSort(arr, left, index-1);
qSort(arr, index+1, right);
}
}
int main()
{
char string[MAX];
while(scanf("%s", string) != -1)
{
qSort(string, 0, strlen(string)-1);
printf("%s\n", string);
}
return 0;
}
#include <stdio.h>
int main()
{
char str[1024] = {0};
while(gets(str))
{
int len = strlen(str);
for (int i = 0; i < len; i++)
{
for (int 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\n", str);
}
return 0;
}
18.寻找数组的中心下标
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。
示例 1:
输入: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 ,二者相等。示例 2:
输入:nums = [1, 2, 3]
输出:-1
解释:
数组中不存在满足此条件的中心下标。示例 3:
输入:nums = [2, 1, -1]
输出:0
解释:
中心下标是 0 。
左侧数之和 sum = 0 ,(下标 0 左侧不存在元素)
右侧数之和 sum = nums[1] + nums[2] = 1 + -1 = 0 。
int pivotIndex(int* nums, int numsSize)
{
int total = 0;
for (int i = 0; i < numsSize; ++i)
{
total += nums[i];
}
int sum = 0;
for (int i = 0; i < numsSize; ++i)
{
if (2 * sum + nums[i] == total)
{
return i;
}
sum += nums[i];
}
return -1;
}
从数组的0下标处开始向后逐下标统计,计算当前下标左边之和,和右边之和,进行判断,相等则为中心下标,如果数组循环结束都没有找到中心下标,则返回-1,表示没有中心下标。
int pivotIndex(int* nums, int numsSize)
{
int i, j;
for (i = 0; i < numsSize; i++)
{ //从假设中心点为0开始进行统计判断
int l_sum = 0, r_sum = 0; //初始化左边之和和右边之和为0
for (j = 0; j < numsSize; j++)
{
if (j < i)
l_sum += nums[j]; //小于i坐标的都是左边的数字
else if (j > i)
r_sum += nums[j]; //大于i坐标的都是右边的数字
}
if (l_sum == r_sum)
{ //如果两遍相等则i就是中心坐标
return i;
}
}
return -1;
}
19.字符个数统计
编写一个函数,计算字符串中含有的不同字符的个数。字符在 ASCII 码范围内( 0~127 ,包括 0 和 127 ),换行表示结束符,不算在字符里。不在范围内的不作统计。多个相同的字符只计算一次
例如,对于字符串 abaca 而言,有 a、b、c 三种不同的字符,因此输出 3 。
数据范围: 1 \le n \le 500 \1≤n≤500
输入描述:
输入一行没有空格的字符串。
输出描述:
输出 输入字符串 中范围在(0~127,包括0和127)字符的种数。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int num=0,len,i,j,k,asc;
int tmp[128]={0};
char str[400];
int main()
{
gets(str);
len=strlen(str);
for(i=0;i<len;i++)
{
asc=(int)str[i];
if(tmp[asc]==0)
{
tmp[asc]=1;
num++;
}
}
printf("%d",num);
return 0;
}
#include <stdio.h>
#include <string.h>
int main()
{
int len;
int count=0;
char str[500];
int arr[128]={0};
scanf("%[^\n]",str);
len=strlen(str);
for(int i=0;i<len;i++)
{
arr[str[i]-0]++;
}
for(int i=0;i<128;i++)
{
if(arr[i]>0)
count++;
}
printf("%d",count);
return 0;
}
这道题思路比较简单,因为题目圈定出现的字符都是 ascii 值小于127的字符,因此只需要定义一个标记数组大小为127 ,然后将字符作为数组下标在数组中进行标记,若数组中没有标记过表示第一次出现,进行计数,否则表示重复字符。
示例:查表法, "aca" ,首先把a字符( ascii 值为 97 )作为下标,将标记数组的第 97 位置 1,下次如果还有 a 字符出现,到下标 'a' 或者 97 的位置一看是1就表示a已经统计过了。
#include <stdio.h>
int main()
{
char tmp[501] = {0};
while(~scanf("%s", tmp))
{
char table[128] = {0}, *ptr = tmp;
int count = 0;
while(*ptr != '\0')
{
if (table[*ptr] != 1)
{ //判断字符ascii值作为下标的位置是否被标记过,是否是重复字符
count++; //当前字符的位置没有被标记过表示没有出现过,则计数+1
}
table[*ptr++] = 1; //将字符ascii值作为下标的位置进行标记置1
}
printf("%d\n", count);
}
return 0;
}
20.多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/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;
}
int copmareFunc(void* a, void* b)
{
//排序算法:
/*返回值需要注意
< 0 elem1将被排在elem2前面
0 elem1 等于 elem2
> 0 elem1 将被排在elem2后面
*/
int* node1 = (int*)a;
int* node2 = (int*)b;
return (*node1 - *node2);
}
int majorityElement(int* nums, int numsSize)
{
//直接快速排序
qsort(nums,numsSize,sizeof(int),copmareFunc);
int targetValue = nums[0];
int targetCnt = 0;
int i;
for( i= 0; i < numsSize ;i ++)
{
if(targetValue != nums[i])
{
targetValue = nums[i];
targetCnt =1;
}
else
{
targetCnt++;
if(targetCnt > numsSize/2)
{
break;
}
}
}
return targetValue;
}
21.自除数
自除数 是指可以被它包含的每一位数除尽的数。
例如,128 是一个 自除数 ,因为 128 % 1 == 0,128 % 2 == 0,128 % 8 == 0。
自除数不允许包含 0 。给定两个整数 left 和 right ,返回一个列表,列表的元素是范围 [left, right] 内所有的 自除数
示例 1:
输入:left = 1, right = 22
输出:[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22]
示例 2:输入:left = 47, right = 85
输出:[48,55,66,77]
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* selfDividingNumbers(int left, int right, int* returnSize)
{
int *res=(int*)malloc(sizeof(int)*(right-left+1));
*returnSize=0;
int f,r=0,t;
for(int i=left;i<=right;i++)
{
f=0;
t=i;
while (t>0)
{
r=t%10;
if (r==0||i%r!=0)
{
f=1;
break;
}
t/=10;
}
if (f==0)
{
res[(*returnSize)++]=i;
}
}
return res;
}
自除数的判断,数字的每一位都能被源数字整除,有了这个规则,咱们只需要循环获取一个数字的每一位,然后与源数字取模判断是否为 0 ,如果中间有任意一次不为 0 ,则表示不是自除数。接下来,只需要遍历数组中的每个元素,判断是否是自除数即可,如果是则加入到返回数组中。
int* selfDividingNumbers(int left, int right, int* returnSize)
{
int *ret = (int *)calloc(1000, sizeof(int));//动态申请足够大的空间用于存放返回的自除数
*returnSize = 0;
for (int i = left; i <= right; i++)
{
int num = i;
while(num)
{
int remainder = num % 10;//计算余数
if (remainder == 0 || (i % remainder) != 0)
{//判断i自身与余数取模是否为0
break;
}
num /= 10;
} //如果num==0表示通过了每一位数的取模判断,则i就是自除数
if (num == 0)
ret[(*returnSize)++] = i;
}
return ret;
}
22.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。
题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。请不要使用除法,且在 O(n) 时间复杂度内完成此题。
示例 1:
输入: nums = [1,2,3,4]
输出: [24,12,8,6]
示例 2:输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]暴力不考虑其他的因素的话,将所有数据乘积起来,然后遍历数组除以当前位置数据即可。
更优解法:将乘积分为两次进行,第一次先将每个位置左边的数据乘积计算出来放到返回数组中,后边第二次循环将对应位置右边的数据乘积计算出来与返回数组对应位置的左半边乘积相乘得到结果。
int left = 1, right = 1;
计算左侧乘积:
第0个元素的左边乘积, arr[0] = left 然后计算第1位左侧乘积 left*=nums[0] -> left = 1*2
left*=nums[1] -> left = 1*2*3
已经没必要了,因为第2元素是末尾元素了
arr[]中的值: [1, 2, 6]第1个元素的左边乘积, arr[1] = left 然后计算第2位左侧乘积 第2个元素的左边乘积, arr[2] = left 然后计算第3位左侧乘积
一次循环完毕后,返回数组中每个元素存储的都是自己左侧元素的乘积。计算右侧乘积: 第2个元素的右边乘积, arr[2] *= right 然后计算第1位右侧乘积
第1个元素的右边乘积, arr[1] *= right 然后计算第0位右侧乘积
第0个元素的右边乘积, arr[0] *= right 然后计算第-1位右侧乘积right*=nums[2] -> right =1*4
right*=nums[1] -> right =1*4*3
-1位已经不需要计算了循环完毕后,返回数组中的每个元素都是其他元素的乘积了 arr[2]*=1; arr[1]*=4; arr[0]*=12
int* productExceptSelf(int* nums, int numsSize, int* returnSize)
{
int *ret = (int *)malloc(numsSize * sizeof(int));
*returnSize = numsSize;
int left = 1, right = 1;
//第一次循环,将当前位置左边的数字乘积填入返回数组中
for (int i = 0; i < numsSize; i++)
{
ret[i] = left;// 1 nums[0] nums[0]*nums[1] num[0]*nums[1]*nums[2] ....
left *= nums[i];
}
//第二次循环,对于返回数组的元素从后往前进行,每次乘以右边元素的乘积
for (int i = numsSize - 1; i >= 0; i--)
{
ret[i] *= right; //最后一个成绩不需要乘以最后元素,乘以1就行
right *= nums[i]; //right变化:1 nums[end] nums[end]*nums[end-1] .....
}
return ret;
}
解题思路
ret[i] = L[i] * R[i]
其中,ret[i]表示数组中除索引i的元素外其他元素的乘积;
L[i] = L[0] * L[1] * ... *L[i - 1],表示索引i元素左侧元素乘积;
R[i] = R[i + 1] * R[i + 2] * ... * R[numsSize - 1],表示索引i元素右侧元素乘积。
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int *productExceptSelf(int *nums, int numsSize, int *returnSize)
{
*returnSize = 0;
if (nums == NULL || numsSize == 0)
{
return NULL;
}
int *ret = (int *)malloc(sizeof(int) * numsSize);
if (ret == NULL)
{
return NULL;
}
int *left_multi = (int *)malloc(sizeof(int) * numsSize);
if (left_multi == NULL)
{
return NULL;
}
left_multi[0] = 1;
int i;
for (i = 1; i < numsSize; i++)
{ // left_multi[i]为nums[i]左侧所有元素的乘积
left_multi[i] = nums[i - 1] * left_multi[i - 1];
}
int *right_multi = (int *)malloc(sizeof(int) * numsSize);
if (right_multi == NULL)
{
return NULL;
}
right_multi[numsSize - 1] = 1;
for (i = numsSize - 2; i >= 0; i--)
{ // right_multi[i]为nums[i]右侧所有元素的乘积
right_multi[i] = nums[i + 1] * right_multi[i + 1];
}
for (i = 0; i < numsSize; i++)
{
ret[i] = left_multi[i] * right_multi[i];
}
*returnSize = numsSize;
return ret;
}
23.不用加减乘除做加法
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
数据范围:两个数都满足 -10 \le n \le 1000−10≤n≤1000
int Add(int num1, int num2 )
{
// write code here
//考察加法原理。不考虑进位+只考虑进位,循环,知道进位位0.
int tmp=num1;
while(num2)
{
tmp;
tmp=num1^num2; //不考虑进位
num2=(num1&num2)<<1; //只考虑进位
num1=tmp;
}
//当进位为0的时候,不考虑进位的和就是整体的和。
return tmp;
}
int Add(int num1, int num2)
{
int sum,temp;
while (num2 != 0)//不进位
{
sum = num1 ^ num2;
temp = (num1 & num2) << 1;
num1 = sum;
num2 = temp;
}
return num1;
}
24.找到所有数组中消失的数字
给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。
int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize)
{
for (int i = 0; i < numsSize; i++)
{
int x = (nums[i] - 1) % numsSize;
nums[x] += numsSize;
}
int* ret = malloc(sizeof(int) * numsSize);
*returnSize = 0;
for (int i = 0; i < numsSize; i++)
{
if (nums[i] <= numsSize)
{
ret[(*returnSize)++] = i + 1;
}
}
return ret;
}
numsSize 大小的数组,其中每个元素的数据在 [1, numsSize] 区间之内,解法其实并不复杂,以数组元素的绝对值作为下标,将对应位置的数据置为负数,比如 0 号位置是 3 ,则把 3 号位置的数据重置为负值,等到数组遍历重置完毕,只有缺失的这个数字对应的位置保留正数,其他出现过的数字位置都会是负数, 要注意不要重复设置负数,因为负负得正。
int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize)
{
for (int i = 0; i < numsSize; i++)
{
if (nums[abs(nums[i]) - 1] > 0)
nums[abs(nums[i]) - 1] = -(nums[abs(nums[i]) - 1]);
}
int *ret = (int *)malloc(sizeof(int) * (numsSize));
*returnSize = 0;
for (int i = 0; i < numsSize; i++)
{
if (nums[i] > 0)
{
ret[*returnSize] = i + 1;
*returnSize += 1;
}
}
return ret;
}
25.给定一个二进制数组, 计算其中最大连续 1 的个数
示例 1:
输入:nums = [1,1,0,1,1,1]
输出:3
解释:开头的两位和最后的三位都是连续 1 ,所以最大连续 1 的个数是 3.
示例 2:输入:nums = [1,0,1,1,0,1]
输出:2
int findMaxConsecutiveOnes(int* nums, int numsSize)
{
int max_count = 0, cur_size = 0;
for (int i = 0; i < numsSize; i++)
{
if (nums[i] == 1)
{
cur_size++;
}
else
{
max_count = max_count > cur_size ? max_count : cur_size;
cur_size = 0;
}
}
max_count = max_count > cur_size ? max_count : cur_size;
return max_count;
}
int findMaxConsecutiveOnes(int* nums, int numsSize)
{
int maxCount = 0, count = 0;
for (int i = 0; i < numsSize; i++)
{
if (nums[i] == 1)
{
count++;
}
else
{
maxCount = fmax(maxCount, count);
count = 0;
}
}
maxCount = fmax(maxCount, count);
return maxCount;
}
26.完全数计算
完全数所有的真因子(即除了自身以外的约数)的和,恰好等于它本身。
例如:28,它有约数1、2、4、7、14、28,除去它本身28外,其余5个数相加,1+2+4+7+14=28。
输入n,请输出n以内(含n)完全数的个数。
#include <stdio.h>
int main()
{
int num = 0;
int res = 0;
while (scanf("%d", &num) != EOF)
{
if(num>=8192)
{
res = 4;
}
else if(num>=496)
{
res = 3;
}
else if(num>=28)
{
res = 2;
}
else if(num>=6)
{
res = 1;
}
printf("%d\n", res);
}
return 0;
}
#include <stdio.h>
#include <math.h>
int is_perfect_num(int num)
{
int sum = 1;
for (int i = 2; i <= sqrt(num); i++)
{
if (num % i == 0)
{ //判断是否能够整除i,能整除则i和结果都是约数
sum += i; //与除数相加
if (i != sqrt(num)) //防止除数和结果相同的情况下重复相加
sum += num / i; //与相除结果相加
}
}
if (sum == num)
return 1;
return 0;
}
int main()
{
int n;
while(~scanf("%d", &n))
{
int count = 0;
for(int i = 2; i <= n; i++)
{ //对n以内的数字都进行判断是否是完全数,注意1不参与判断
if (is_perfect_num(i))
count++;
}
printf("%d\n", count);
}
return 0;
}
27.数字颠倒
输入一个整数,将这个整数以字符串的形式逆序输出。
程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001。
#include<stdio.h>
int main()
{
long n=0;
scanf("%d",&n);
if(n==0)
printf("%d",n);
while(n)
{
printf("%d",n%10);
n/=10;
}
return 0;
}
#include <stdio.h>
int main()
{
char out[20] = { 0 };
int n = 0;
int len = 0;
scanf("%d", &n);
out[0] = '0';
while (n)
{
len += sprintf(out + len, "%d", n % 10);
n /= 10;
}
printf("%s\n", out);
return 0;
}
#include <stdio.h>
int main()
{
int num;
while(~scanf("%d", &num))
{
if (num == 0)
{ //0的情况特殊处理,因为0不会进入while循环计算余数,因此不会被打印
printf("%d", num % 10);
continue;
}
while(num > 0)
{
printf("%d", num % 10);//打印一个数字的个位数 129 % 10 得到9
num /= 10;//通过除以10的方式去掉个位数 例如:129/10 得到12
}
printf("\n");
}
return 0;
}
28.对字符串中的所有单词进行倒排
说明:
1、构成单词的字符只有26个大写或小写英文字母;
2、非构成单词的字符均视为单词间隔符;
3、要求倒排后的单词间隔符以一个空格表示;如果原字符串中相邻单词间有多个间隔符时,倒排转换后也只允许出现一个空格间隔符;
4、每个单词最长20个字母;
输入:I am a student
输出:student a am I
输入:$bo*y gi!r#l
输出:l r gi y bo
#include "stdio.h"
int main()
{
char s[10000] = {0};
char chr = 0;
int len = 0;
int flag = 0;
int end=0,start=0;
int first = 0;
while (1)
{
scanf("%c", &chr);
if (chr == '\n')
break;
s[len++] = chr;
}
for (int i=len;i>0;i--)
{
if ((s[i-1] >= 'a' && s[i-1] <= 'z') || (s[i-1] >= 'A' && s[i-1] <= 'Z'))
{
if (flag == 0)
{
flag = 1;
end = i;
}
}
else
{
if (flag == 1)
{
flag = 0;
start = i;
if (first == 0)
first = 1;
else
printf(" ");
for (int j=start;j<end;j++)
printf("%c",s[j]);
start = 0;
end = 0;
}
}
if (i==1 )
{
if (end != 0)
{
printf(" ");
for (int j=start;j<end;j++)
printf("%c",s[j]);
}
printf("\n");
}
}
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
char str[5000];
gets(str);
int len = strlen(str);
int flag = 0;
int dp[5000] = {0};
for (int i = 0; i < len; i++)
{
if (((str[i] >= 'A') && (str[i] <= 'Z')) || ((str[i] >= 'a') && (str[i] <= 'z')))
{
dp[i] = 1;
}
}
int num = 0;
for (int i = len - 1; i >= 0; i--)
{
if (dp[i] == 1) //是字母
{
num++;
if (i == 0)
{
for (int j = 0; j < num; j++)
{
printf("%c", str[i + j]);
}
}
}
else
{
for (int j = 0; j < num; j++)
{
printf("%c",str[i+j+1]);
}
num = 0;
printf(" ");
}
}
return 0;
}
定义一个字符指针数组,用于保存每个单词的起始字符地址,接下来将非字母字符全部替换
成为字符串结尾标志,则单词字符字母遇到结尾就结束了,相当于把一个字符串以非字母字符进行切割成为了多个字符串,最终对字符指针数组进行逆序打印每个单词即可
#include <stdio.h>
#include <string.h>
int main()
{
char str[10001] = {0};//字符串最长10000
int row = 0;
while(gets(str) > 0)
{
char *ptr = str;
char *word[10000] = {NULL};
while(*ptr != '\0')
{
//如果是个字母字符,则是单词的起始字符
if (('z' >= *ptr && *ptr >= 'a') || ('Z' >= *ptr && *ptr >= 'A'))
{
word[row++] = ptr;//保存每个单词的起始地址
//把本次的单词字母字符走完,直到遇到非字母字符
while(*ptr != '\0' &&(('z' >= *ptr && *ptr >= 'a') ||('Z' >= *ptr && *ptr >= 'A')))
{
ptr++;
}
continue;//不能继续向下,因为下边的ptr++会跳过当前的非字母字符
}
*ptr = '\0';//把非字母的数据全部替换为结尾标志
ptr++;
}
for (int i = row - 1; i >= 0; i--)
{
printf("%s ", word[i]);//针对所有单词的起始地址逆序开始打印即可
}
printf("\n");
}
}
29.统计每个月兔子的总数
有一只兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子,假如兔子都不死,问第n个月的兔子总数为多少?
#include <stdio.h>
int main()
{
int n;
while(~scanf("%d", &n))
{
int num1 = 1, num2 = 1, ret = 0;
for (int i = 2; i < n; i++)
{
ret = num1 + num2;
num1 = num2;
num2 = ret;
}
printf("%d\n", ret);
}
return 0;
}
#include <stdio.h>
int main()
{
int input,value[31]={0},i;
value[1]=value[2]=1;
//printf("%d\n",value[1]);
//printf("%d\n",value[2]);
for(i=3;i<=31;i++)
{
value[i]=value[i-1]+value[i-2];
}
while(scanf("%d",&input)!=EOF)
{
printf("%d\n",value[input]);
}
return 0;
}
30.数列的和
数列的第一项为n,以后各项为前一项的平方根,求数列的前m项的和。
输入描述:
输入数据有多组,每组占一行,由两个整数n(n<10000)和m(m<1000)组成,n和m的含义如前所述。
输出描述:
对于每组输入数据,输出该数列的和,每个测试实例占一行,要求精度保留2位小数。
求取一个数字的平方根可以使用数学库中的 double sqrt(double num) 函数完成,接下来只需要从数字自身开始进行求和并在求和后将 n 自身计算成为自身的平方根即可。
#include <stdio.h>
#include <math.h>
int main()
{
double m, n;
while(~scanf("%lf %lf", &n, &m))
{
double sum=0;
while(m-- > 0)
{
sum += n;//从自身开始以及每次的平方根进行求和
n = sqrt(n);//n成为当前自身的平方根
}
printf("%.2lf\n", sum);
}
return 0;
}
#include<stdio.h>
#include<math.h>
int n,m;
double sqr(double n)
{
double k=1.0;
while(fabs(k*k-n)>1e-9)
{
k=(k+n/k)/2;
}
return k;
}
void fun()
{
while (scanf("%d %d",&n,&m)!=EOF)
{
double sum=n*1.0,t=n*1.0;
for(int i=2;i<=m;i++)
{
t=sqr(t);
sum+=t;
}
printf("%.2f\n",sum);
}
}
int main()
{
fun();
return 0;
}
#include <stdio.h>
#include <math.h>
double sqr(double n)
{
double k=1.0;
while(fabs(k*k-n)>1e-9)
{
k=(k+n/k)/2;
}
return k;
}
int main()
{
int m = 0;
int n = 0;
while(~scanf("%d%d",&n,&m))
{
double sum = n * 1.0;
double tmp = n * 1.0;
for(int i = 1; i < m;i++)
{
tmp = sqr(tmp);
sum +=tmp;
}
printf("%.2f\n",sum);
}
return 0;
}
31.珠玑妙算
计算机有4个槽,每个槽放一个球,颜色可能是红色(R)、黄色(Y)、绿色(G)或蓝色(B)。例如,计算机可能有RGGB 4种(槽1为红色,槽2、3为绿色,槽4为蓝色)。作为用户,你试图猜出颜色组合。打个比方,你可能会猜YRGB。要是猜对某个槽的颜色,则算一次“猜中”;要是只猜对颜色但槽位猜错了,则算一次“伪猜中”。注意,“猜中”不能算入“伪猜中”。
给定一种颜色组合solution和一个猜测guess,编写一个方法,返回猜中和伪猜中的次数answer,其中answer[0]为猜中的次数,answer[1]为伪猜中的次数。
输入: solution="RGBY",guess="GGRR" 输出: [1,1] 解释: 猜中1次,伪猜中1次。提示:
len(solution) = len(guess) = 4
solution
和guess
仅包含"R"
,"G"
,"B"
,"Y"
这4种字符
#define MAX_NUM (2)
#define MAX_LENTH (4)
int answer[MAX_NUM] = {0};
#define FOUND 'F'
int* masterMind(char* solution, char* guess, int* returnSize)
{
int i, j;
for (i = 0; i < MAX_NUM; i++)
{
answer[i] = 0;
}
for (i = 0; i < MAX_LENTH; i++)
{
if (solution[i] == guess[i])
{
answer[0]++;
guess[i] = FOUND;
solution[i] = FOUND + 2;
}
}
for (i = 0; i < MAX_LENTH; i++)
{
for (j = 0; j < MAX_LENTH; j++)
{
if(solution[i] == guess[j])
{
answer[1]++;
guess[j] = FOUND;
break;
}
}
}
*returnSize = MAX_NUM;
return answer;
}
遍历两个数组,统计猜中次数和伪猜中次数
猜中次数:若位置相同且颜色字符也相同在猜中次数计数器+1
伪猜中次数:颜色相同,但是在不同位置,这时候只需要除去猜中位置之外,统计两个数组中各个字符出现的数量,取较小的一方就是每种颜色伪猜中的数量了。
int* masterMind(char* solution, char* guess, int* returnSize)
{
*returnSize = 2;
static int arr[2] = {0};
arr[0] = 0; arr[1] = 0;//静态空间不会进行二次初始化因此每次重新初始化,可以使用memset函数
int s_arr[26] = {0};//26个字符位 solution 四种颜色数量统计
int g_arr[26] = {0};//26个字符位 guess 四种颜色数量统计
for (int i = 0; i < 4; i++)
{
if (solution[i] == guess[i])
{
arr[0] += 1;//位置和颜色完全一致则猜中数量+1
}
else
{
//统计同一位置不同颜色的两组颜色数量,伪猜中不需要对应位置相同,只需要有对应数量的颜色就行
s_arr[solution[i]-'A'] += 1; //统计solution对应颜色字符出现次数
g_arr[guess[i]-'A'] += 1; //统计guess对应颜色字符出现次数
}
} //在两个颜色数量统计数组中查看颜色数量,取相同位置较小的一方就是为猜中数量
for (int i = 0; i < 26; i++)
{
arr[1] += s_arr[i] > g_arr[i] ? g_arr[i] : s_arr[i];
}
return arr;
}
32. 两数之和
给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。
(注:返回的数组下标从1开始算起,保证target一定可以由数组里面2个数字相加得到)
输入:[3,2,4],6
返回值:[2,3]
说明:因为 2+4=6 ,而 2的下标为2 , 4的下标为3 ,又因为 下标2 < 下标3 ,所以返回[2,3]
输入:[20,70,110,150],90
返回值:[1,2]
说明:20+70=90
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param numbers int整型一维数组
* @param numbersLen int numbers数组长度
* @param target int整型
* @return int整型一维数组
* @return int* returnSize 返回数组行数
*
* C语言声明定义全局变量请加上static,防止重复定义
*/
static int res[2];
int* twoSum(int* numbers, int numbersLen, int target, int* returnSize )
{
// write code here
int i = 0;
int j = 0;
*returnSize = 2;
for(i = 0; i < numbersLen; i++)
{
if (numbers[i] > target)
continue;
for(j = i + 1; j < numbersLen; j++)
{
if(numbers[i] + numbers[j] == target)
{
res[0] = i + 1;
res[1] = j + 1;
}
}
}
return res;
}
在数组中拿到一个数字 num 后,在剩下的数字中查找是否有等于 target - num 的数字即可
int* twoSum(int* numbers, int numbersLen, int target, int* returnSize )
{
*returnSize = 2;
static ret_arr[2] = {0};
memset(ret_arr, 0x00, sizeof(ret_arr));//静态空间不会二次初始化,因此手动初始化
for (int i = 0; i < numbersLen; i++)
{ //从第0个位置开始一个一个数字找
for (int j = i + 1; j < numbersLen; j++)
{ //从第一个数字往后的数字中找出另一个数字
//与numbers[i]相加等于target的数字找到了则i和j就是对应两个数字下标
if (numbers[i] + numbers[j] == target)
{
ret_arr[0] = i + 1;//题目要求下标从1开始
ret_arr[1] = j + 1;
return ret_arr;
}
}
}
*returnSize = 0;//没有符合的下标则返回数组大小为0;
return NULL;
}
33.寻找奇数
现在有一个长度为 n 的正整数序列,其中只有一种数值出现了奇数次,其他数值均出现偶数次,请你找出那个出现奇数次的数值。
输入描述:
第一行:一个整数n,表示序列的长度。第二行:n个正整数ai,两个数中间以空格隔开。
输出描述:
一个数,即在序列中唯一出现奇数次的数值。
#include<stdio.h>
int main()
{
int n = 0;
int ans = 0;
scanf("%d",&n);
for(int i = 0; i < n; i++)
{
int tmp = 0;
scanf("%d",&tmp);
ans ^= tmp;
}
printf("%d\n", ans);
return 0;
}
#include <stdio.h>
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int sum=0,num;
while(n--)
{
scanf("%d",&num);
sum^=num;
}
printf("%d\n",sum);
}
return 0;
}
异或:二进制比特位相同则0, 不同则1.
两个相同的数字异或得到的是0, 基于这个思路,这道题对数组中的所有数据进行逐一异或就可以解决得到奇数次的数字,因为偶数次的数字都被异或成为0了,最后单独保留了奇数次的数字。
#include <stdio.h>
int main()
{
int n;
while(~scanf("%d", &n))
{
int num = 0, tmp = 0;
//对每个数字进行异或,出现偶数次的就会异或为0了,而奇数次刚好剩下的就是对应数字
for (int i = 0; i < n; i++)
{
scanf("%d", &tmp);
num ^= tmp;
}
printf("%d\n", num);
}
return 0;
}
34.寻找峰值
给定一个长度为n的数组nums,请你找到峰值并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个所在位置即可。
1.峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于
2.假设 nums[-1] = nums[n] = -\infty−∞
3.对于所有有效的 i 都有 nums[i] != nums[i + 1]
4.你可以使用O(logN)的时间复杂度实现此问题吗?
如输入[2,4,1,2,7,8,4]时,会形成两个山峰,一个是索引为1,峰值为4的山峰,另一个是索引为5,峰值为8的山峰,如下图所示:
输入:[2,4,1,2,7,8,4]
返回值:1
说明:4和8都是峰值元素,返回4的索引1或者8的索引5都可以
输入:[1,2,3,1]
返回值:2
说明:3 是峰值元素,返回其索引 2
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型一维数组
* @param numsLen int nums数组长度
* @return int整型
*
* C语言声明定义全局变量请加上static,防止重复定义
*/
int findPeakElement(int* nums, int numsLen )
{
// write code here
int count = 0;
int* arr = malloc(sizeof(int) * (numsLen + 2));
arr[0] = -1;
arr[1] = 0;
arr[numsLen - 1] = -1;
for (int i = 1; i < numsLen; i++)
{
if (nums[i - 1] < nums[i])
{
count++;
arr[i + 1] = count;
}
if (nums[i - 1] > nums[i])
{
count--;
arr[i + 1] = count;
}
if (nums[i - 1] == nums[i])
{
arr[i + 1] = count;
}
}
for (int i = 1; i < numsLen+1; i++)
{
if (arr[i] > arr[i - 1] && arr[i] > arr[i + 1])
{
return i - 1;
}
}
return 0;
}
int findPeakElement(int* nums, int numsLen )
{
//边界情况处理,1个元素前后都是负无穷 以及 0号位置大于1号位置,-1位置负无穷的情况
if (numsLen == 1 || nums[0] > nums[1])
return 0;
//末尾位置数据大于上一个位置数据,而nums[numsLen]负无穷的情况
if (nums[numsLen-1] > nums[numsLen-2])
return numsLen-1;
int left = 0, right = numsLen - 1, mid;
while(left < right)
{
mid = left + (right - left) / 2;
if (nums[mid] < nums[mid + 1])//中间比右边小,意味着右边肯定有个峰值
left = mid + 1;
else //否则在左边包括当前位置肯定有个峰值
right = mid;
}
return left;
}
35.数对
牛牛以前在老师那里得到了一个正整数数对(x, y), 牛牛忘记他们具体是多少了。但是牛牛记得老师告诉过他x和y均不大于n, 并且x除以y的余数大于等于k。牛牛希望你能帮他计算一共有多少个可能的数对。
输入:5 2
输出:7
说明:满足条件的数对有(2,3),(2,4),(2,5),(3,4),(3,5),(4,5),(5,3)
int main()
{
int n,k;
scanf("%d%d",&n,&k);
int ret=n-k;
unsigned long long count=0;
if(k==0)
count=(long long)n*n;
else
{
for(int i=1;i<=ret;i++)
{
count+=i;
int j=n%(i+k)-k+1;
int z=(n/(i+k)-1)*i;
if(j>=0)
count=count+j+z;
else
count=count+z;
}
}
printf("%llu\n",count);
return 0;
}
#include<stdio.h>
int main()
{
int n,k;
scanf("%d%d",&n,&k);
if(k==0)
{
printf("%lld",(long long )n*n);
return 0;
}
long long c=0;
for(int y=k+1;y<=n;y++)
{
int remain=n%y-(k-1);
if(remain<0) remain=0;
c+=remain+(y-k)*(n/y);
}
printf("%lld",c);
return 0;
}
#include <stdio.h>
int main()
{
long n, k;
while(~scanf("%ld %ld", &n, &k))
{
if (k == 0)
{
printf("%ld\n", n * n);//任意数对的取模结果都是大于等于0的
continue;
}
long count = 0;
for(long y = k + 1; y <= n; y++)
{
count += ((n / y) * (y - k)) + ((n % y < k) ? 0 : (n % y - k + 1));
}
printf("%ld\n", count);
}
return 0;
}
36.截取字符串
输入一个字符串和一个整数 k ,截取字符串的前k个字符并输出
输入描述:1.输入待截取的字符串 2.输入一个正整数k,代表截取的长度
输出描述:截取后的字符串
输入:abABCcDEF 6
输出:abABCc
输入:ffIKEHauv 1 bdxPKBhih 6
输出:f bdxPKB
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char str[1000];
while( scanf("%s", &str) != EOF )
{
int n;
scanf("%d", &n);
int cnt = 0;
int i=0;
while( cnt+sizeof(str[i]) <= n )
{
printf("%c",str[i++]);
cnt += sizeof(str[i]);
}
printf("\n");
}
return 0;
}
#include<stdio.h>
int main()
{
char a[1000]={0};
while(scanf("%s",a)!=EOF)
{
int k;
scanf("%d",&k);
int i;
for(i=0;i<k;i++)
{
printf("%c",a[i]);
}
printf("\n");
}
return 0;
}
截取字符串前 n 个字符,只需要将数组 n 下标位置的数据替换为字符串结尾标志即可
#include <stdio.h>
int main()
{
char str[101];
while(scanf("%s", str) > 0)
{
int n;
scanf("%d", &n);
str[n] = '\0';
printf("%s\n", str);
}
return 0;
}
37.倒置字符串
将一句话的单词进行倒置,标点不倒置。 I like beijing. beijing. like I
1、先整体逆置
2、从头开始每个单词逆置,需要注意,最后一个单词结尾不是空格。C/C++就是\0.Java通过长度来判断。
3、C/C++注意,不要逆置了\0 . Java 注意通过长度判断句子结束
#include<stdio.h>
#include<string.h>
void Reverse(char *start,char *end)
{
while(start < end)
{
char tmp = *start;
*start = *end;
*end = tmp;
start++;
end--;
}
}
int main()
{
char input[100];
gets(input);
//1.整体逆置
Reverse(input,input+strlen(input)-1);
char *start = input;
char *end = input;
while(*start != '\0')
{
while(*end != ' ' && *end != '\0')
{
end++;
}
if(*end == ' ')
{
Reverse(start, end-1);
end++;
start = end;
}
else
{
Reverse(start, end-1);
start = end;
}
}
printf("%s\n",input);
return 0;
}
38.喝汽水,1瓶汽水1元,2个空瓶可以换一瓶汽水,给20元,可以多少汽水
#include <stdio.h>
int Num(int num)
{
static int more = 0;
if (more == 1 && num == 1)
{//终止条件是more 和 num 都为 1
return 1;
}
if (more == 1)
{//如果是奇数 ,上次有一个空瓶没有兑换, 则需要在下一步减 1,不然会多加一瓶水
num = num - 1;
}
more = num % 2;//如果此次的水是奇数,则在下一个循环 num 需要减掉 1
return num + Num(num / 2 + more);
//加的 more 是没有兑换的空瓶 如果为 1,则需要在下一层减 1
}
int main()
{
int ret = Num(20);
//int ret = Num2(20);
printf("%d\n", ret);
return 0;
}
39.调整数组使奇数全部都位于偶数前面。
输入一个整数数组,实现一个函数,来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分,所有偶数位于数组的后半部分
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
//调整数组使奇数全部都位于偶数前面
void Depart_Arry(int arr[], int size)
{
int left = 0;
int right = size - 1;
while (left < right)
{
//从前到后找偶数
while (left < right&&arr[left] % 2 != 0)
{
left++;
}
//从后到前找奇数
while (left < right&&arr[right] % 2 == 0)
{
right--;
}
//交换
if (left < right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
}
}
}
//打印数组
void Print(int arr[], int size)
{
for (int i = 0; i < size; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[] = { 2, 3, 4, 6, 5, 8, 7, 10, 9, 1 };
int size = sizeof(arr) / sizeof(arr[0]);
Depart_Arry(arr, size);
Print(arr, size);
system("pause");
return 0;
}
40.VS开发环境调试下面的代码,画图解释下面代码的问题
#include <stdio.h>
int main()
{
int i = 0;
int arr[] = {1,2,3,4,5,6,7,8,9,10};
for(i=0; i<=12; i++)
{
arr[i] = 0;
printf("hello bit\n");
}
return 0;
}
41.下面代码的结果
int main()
{
char a[1000] = {0};
int i=0;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
return 0;
}
42.打印杨辉三角
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i,j,n = 0;
//首先定义二维数组计数符号i,j 还有杨辉三角行数的初始化
int a[100][100] = {0};
//二维数组大小可自定,但切记不可使其超过整形数组的大小
while(n < 1 || n >100)
//在输入的值不正确时自动初始化问题,重新输入
{
printf("请输入要打印的杨辉三角行数>:");
scanf("%d",&n);
}
for(i = 0; i < n ; i++)
{
a[i][0] = 1;
//每一行第一个为1,用第一个for循环的输入
}
for(i = 1; i < n; i++ )//第一层循环i决定第几行
{
for(j = 1; j <= i; j++)//第二层循环借用i限制每行字符数目
{
a[i][j] = a[i-1][j-1]+a[i-1][j];
}
}
for(i = 0; i < n; i++)//一个for循环逐行打印叫a的二维数组
{
for(j = 0; j <= i; j++)
printf("%5d",a[i][j]);
printf("\n");
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i,j,n = 0;
//首先定义二维数组计数符号i,j 还有杨辉三角行数的初始化
int a[100][100] = {1};
//二维数组大小可自定,但切记不可使其超过整形数组的大小
while(n < 1 || n >100)
//在输入的值不正确时自动初始化问题,重新输入
{
printf("请输入要打印的杨辉三角行数>:");
scanf("%d",&n);
}
for(i = 1; i < n; i++ )//第一层循环i决定第几行
{
a[i][0] = 1;
for(j = 1; j <= i; j++)//第二层循环借用i限制每行字符数目
{
a[i][j] = a[i-1][j-1]+a[i-1][j];
}
}
for(i = 0; i < n; i++)//一个for循环逐行打印叫a的二维数组
{
for(j = 0; j <= i; j++)
printf("%5d",a[i][j]);
printf("\n");
}
return 0;
}
//把每一行的第一个初始化1的操作包入第一个for循环中,并且改动二维数组初始化值为1
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i,j,n = 0;
//首先定义二维数组计数符号i,j 还有杨辉三角行数的初始化
int a[100][100] = {0,1};
//只有2个初值,即a[0][0]=1,a[0][1]=2,其余数组元素的初值均为0
//二维数组大小可自定,但切记不可使其超过整形数组的大小
while(n < 1 || n >100)
//在输入的值不正确时自动初始化问题,重新输入
{
printf("请输入要打印的杨辉三角行数>:");
scanf("%d",&n);
}
for(i = 1; i < n; i++ )//第一层循环i决定第几行
{
for(j = 1; j <= i; j++)//第二层循环借用i限制每行字符数目
{
a[i][j] = a[i-1][j-1]+a[i-1][j];
}
}
for(i = 1; i < n; i++)//一个for循环逐行打印叫a的二维数组
{
for(j = 1; j <= i; j++)
printf("%5d",a[i][j]);
printf("\n");
}
return 0;
}
//优化于方法一二,取消二维数组中第一列赋值为1的做法,且在最后输出时略有改动
//int a[100][100] = {0,1};此处赋值知识已单独开设一文,请自行查找本人博客
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i,j,n = 0;
//首先定义二维数组计数符号i,j 还有杨辉三角行数的初始化
int a[100][100] = {0,1};
//二维数组大小可自定,但切记不可使其超过整形数组的大小
while(n < 1 || n >100)
//在输入的值不正确时自动初始化问题,重新输入
{
printf("请输入要打印的杨辉三角行数>:");
scanf("%d",&n);
}
for(i = 1; i < n; i++ )//第一层循环i决定第几行
{
for(j = 1; j <= i; j++)//第二层循环借用i限制每行字符数目
{
a[i][j] = a[i-1][j-1]+a[i-1][j];
printf("%5d",a[i][j]);
}
printf("\n");
}
return 0;
}
//优化于解法三,仅将赋值输出同时进行,且注意换行符的位置更替。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i,j,n = 0;
//首先定义二维数组计数符号i,j 还有杨辉三角行数的初始化
int a[100] = {1};
int b[100] = {0};
while(n < 1 || n >100)
//在输入的值不正确时自动初始化问题,重新输入
{
printf("请输入要打印的杨辉三角行数>:");
scanf("%d",&n);
}
for(i = 0; i < n; i++ )
{
b[0] = a[0];
for(j = 1; j <= i; j++)
{
b[j] = a[j-1]+a[j];
}
for(j = 0; j <= i; j++)
{
a[j] = b[j];
printf("%5d",a[j]);
}
printf("\n");
}
return 0;
}
//解法五不同于前者,使用两个一维数组能够较好的节省空间,方法可行,but运行方式有待我仔细酌定。
望见谅,后续更新
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i,j,n = 0;
int l,r;
//首先定义二维数组计数符号i,j 还有杨辉三角行数的初始化
int a[100] = {0,1};
while(n < 1 || n >100)
//在输入的值不正确时自动初始化问题,重新输入
{
printf("请输入要打印的杨辉三角行数>:");
scanf("%d",&n);
}
for(i = 1; i < n; i++ )
{
l = 0;
for(j = 1; j <= i; j++)
{
r = a[j];
a[j] = l + r;
l = r;
printf("%5d",a[j]);
}
printf("\n");
}
return 0;
}
//解法六使用一个一维数组,再加两个临时变量进行操作
43.猜凶手
MurderT()
{
//0代表不是凶手,1代表是凶手
int A = 0;
int B = 0;
int C = 0;
int D = 0;//均初始化为0
int CD = 0;//CD说话为对立的,因此需要做标记排除
int i = 0;
for (i; i < 4; i++)
{
if (i == 0)//假如A说的是假话
{
A = 1;
C = 1;
D = 0;
CD = 1;
}
else if (i == 1)//假如B说假话
{
A = 0;
C = 0;
D = 0;
CD = 1;
}
else if (i == 2)//假如C说假话
{
A = 0;
C = 1;
D = 0;
CD = 0;
}
else if (i == 3)//假如D说假话
{
A = 0;
C = 1;
D = 1;
CD = 0;
}
if (A + B + C + D + CD == 1 && CD == D)
//A + B + C + D + CD == 1代表满足只有一个人是凶手条件才可以,CD==D用来排除C和D矛盾的条件
{
printf("A=%d B=%d C=%d D=%d\n", A, B, C, D);
}
}
}
#include<stdio.h>
#include<windows.h>
Murder()//谋杀案
{
char k;//代表凶手
for (k = 'A'; k <= 'D'; k++)//让凶手四人分别去验证if条件,满足条件者就是凶手
{
if (3 == ((k != 'A') + (k == 'C') + (k == 'D') + (k != 'D')))//只有满足三个人说真话,一个假话,他们之和为3这个条件,就能确定此人是凶手
{
printf("凶手是:%c\n", k);
}
}
}
int main()
{
Murder();//谋杀案
system("pause");
return 0;
}
44.猜名次
5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果:
A选手说:B第二,我第三;
B选手说:我第二,E第四;
C选手说:我第一,D第二;
D选手说:C最后,我第三;
E选手说:我第四,A第一;
比赛结束后,每位选手都说对了一半,请编程确定比赛的名次。
#include<stdio.h>
#include<windows.h>
int main()
{
int a, b, c, d, e;
for (a = 1; a <= 5; a++)
{
for (b = 1; b <= 5; b++)
{
for (c = 1; c <= 5; c++)
{
for (d = 1; d < 5; d++)
{
for (e = 1; e < 5; e++)
{
if (a*b*c*d*e==120)
{
if (((b == 2) + (a == 3)==1)&&
((b == 2) + (e == 4)==1)&&
((c == 1) + (d == 2)==1)&&
((c == 5) + (d == 3)==1)&&
((e == 4) + (a == 1)==1))
{
printf("a=%d,b=%d,c=%d,d=%d,e=%d\n", a, b, c, d, e);
}
}
}
}
}
}
}
system("pause");
return 0;
}
45.2的n次方计算
不使用累计乘法的基础上,通过移位运算(<<)实现2的n次方的计算。
#include<stdio.h>
int main()
{
int n;
while(scanf("%d", &n) != EOF)
{
printf("%d\n", 1 << n );
}
return 0;
}
46.公务员面试
公务员面试现场打分。有7位考官,从键盘输入若干组成绩,每组7个分数(百分制),去掉一个最高分和一个最低分,输出每组的平均成绩。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void sort(int* arr,int n)
{
int i = 0;
int j = 0;
int temp = 0;
for (i = 0; i < n - 1; i++)
{
for (j = 0; j < n - i - 1; j++)
{
if (*(arr+j) > *(arr+j+1))
{
temp = *(arr + j);
*(arr + j) = *(arr + j + 1);
*(arr + j + 1) = temp;
}
}
}
}
int main()
{
int arr[7] = { 0 };
int n = 7;
int i = 0;
float sum = 0;
float ave = 0;
while (scanf("%d %d %d %d %d %d %d", &arr[0], &arr[1], &arr[2], &arr[3], &arr[4], &arr[5], &arr[6]) != EOF)
{
sum = 0;
sort(arr,n);
for (i = 1; i < n - 1; i++)
{
sum += arr[i];
}
ave = sum / (n - 2);
printf("%.2f\n", ave);
}
}
#include<stdio.h>
int main()
{
int arr[7] = {0};
while(scanf("%d %d %d %d %d %d %d",&arr[0], &arr[1], &arr[2], &arr[3],
&arr[4], &arr[5], &arr[6]) != EOF)
{
int max = 0;
int min = 100;
double sum = 0;
for(int i = 0; i < 7; i++)
{
sum += arr[i];
if(arr[i] > max)
max = arr[i];
if(arr[i] < min)
min = arr[i];
}
sum = sum - max - min;
printf("%.2f\n",sum/5.0);
}
return 0;
}
47.获得月份天数
输入年份和月份,计算这一年这个月有多少天。
#include<stdio.h>
int main()
{
int y,m,day;
int d[12]={31,28,31,30,31,30,31,31,30,31,30,31};
while(~scanf("%d %d",&y,&m))
{
day=d[m-1];
if(y%400==0||y%4==0&&y%100!=0)
{
if(m==2)
day++;
}
printf("%d\n",day);
}
return 0;
}
#include<stdio.h>
int main()
{
int year,month;
while(~scanf("%d %d",&year,&month))
{
int flg=0;
if((year%400==0)||(year % 4 == 0 && year %100!=0))
flg=1;
if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)
printf("31\n");
else if(month==2)
{
if(1==flg)
printf("29\n");
else if(0==flg)
printf("28\n");
}
else
printf("30\n");
}
return 0;
}
48.变种水仙花
变种水仙花数 - Lily Number:把任意的数字,从中间拆分成两个数字,比如1461 可以拆分成(1和461),(14和61),(146和1),如果所有拆分后的乘积之和等于自身,则是一个Lily Number。
例如:
655 = 6 * 55 + 65 * 5
1461 = 1*461 + 14*61 + 146*1
求出 5位数中的所有 Lily Number。
#include <stdio.h>
int main()
{
int i;
for(i=10000;i<=100000;i++)\
{
if(i==((i/10000)*(i%10000))+((i/1000)*(i%1000))+((i/100)*(i%100))+((i/10)*(i%10)))
printf("%d ",i);
}
return 0;
}
49.判断字母
从键盘任意输入一个字符,编程判断是否是字母(包括大小写)。
#include <stdio.h>
int main()
{
int ch = 0;
while( ( ch = getchar() ) != EOF )
{
//判断字母
if((ch>='A' && ch<='Z') || (ch>='a'&& ch<='z'))
//if(isalpha(ch))
printf("YES\n");
else
printf("NO\n");
//清楚 \n
getchar();
}
return 0;
}
#include<stdio.h>
int main()
{
char ch = 0;
while(scanf("%c", &ch)!=EOF)
{
getchar();
if((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
50.实现一个函数,可以左旋字符串中的k个字符
例如:ABCD左旋一个字符得到BCDA ABCD左旋两个字符得到CDAB
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
//交换函数
int Swap(char* start, char* end)
{
char temp;
if (start == end)
{ //若字符串为空
printf("字符串为空.\n"); //输出提示信息
return 0;
}
--end; //使end指向字符串最后一个有效字符
while (start < end)
{ //当start小于end
//交换start和end指向的内容
temp = *start;
*start = *end;
*end = temp;
++start; //start向后移
--end; //end向前移
}
return 1;
}
//用户输入数据函数
int input_breakpoint(int len)
{
int breakpoint;
printf("请输入您想左旋字符个数(0-%d):\n", len - 1); //提示用户输入信息
while (1)
{ //当条件为真
scanf("%d", &breakpoint);
if (breakpoint >= 0 && breakpoint < len)
{ //判断断点是否合格
break; //断点合格跳出循环
}
printf("输入有误,请重新输入(0-%d):\n", len - 1); //提示用户重新输入信息
}
return breakpoint; //返回断点
}
//实现函数
void Function(char str[],int len)
{
char* start = str; //start指向字符串开头
char* end = str + len - 1; //end指向'\0'
Swap(start, end);
int breakpoint = input_breakpoint(len);
end = end - breakpoint; //end向左移end减breakpoint位(即将breakpoint个字符左旋)
Swap(start, end);
start = end; //start指向end
while (*end != '\0')
{ //当end指向不为空
++end; //end向后移
}
Swap(start, end);
printf("%s", str);
}
//主函数
int main()
{
char str[] = "ABCD"; //定义字符串,并初始化
int len = sizeof(str);
Function(str,len); //调用实现函数
system("pause");
return 0;
}
设计循环使其可以旋1次,然后让他执行n次是一个最简单的思路
void leftRound(char * src, int time)
{
int i, j, tmp;
int len = strlen(src);
time %= len;
//长度为5的情况下,旋转6、11、16...次相当于1次,7、12、17...次相当于2次,以此类推。
for (i = 0; i < time; i++) //执行k次的单次平移
{
tmp = src[0];
for(j = 0; j < len - 1; j++) //单次平移
{
src[j] = src[j + 1];
}
src[j] = tmp;
}
}
改进一:这个思路当然可以,但是一次一次转毕竟太麻烦,就不能一次到位么?当然可以,我们可以选择拼接法,一次到位:
void leftRound(char * src, int time)
{
int len = strlen(src);
int pos = time % len; //断开位置的下标
char tmp[256] = { 0 }; //更准确的话可以选择malloc len + 1个字节的空间来做这个tmp
strcpy(tmp, src + pos); //先将后面的全部拷过来
strncat(tmp, src, pos); //然后将前面几个接上
strcpy(src, tmp); //最后拷回去
}
改进二:
这个方法要用到一个数组形成的辅助空间,让人觉得有点不爽,还可以有更好的选择,例如ABCDEFG,左旋3次后变成DEFGABC,有一个特殊的操作方式:先将要左旋的前三个家伙逆序(CBADEFG),然后将后半段也逆序(CBAGFED),最后整体逆序(DEFGABC)即可。这样只需要做数值交换即可,可以写一个函数帮我们完成局部逆序,代码如下:
void reverse_part(char *str, int start, int end) //将字符串从start到end这一段逆序
{
int i, j;
char tmp;
for (i = start, j = end; i < j; i++, j--)
{
tmp = str[i];
str[i] = str[j];
str[j] = tmp;
}
}
void leftRound(char * src, int time)
{
int len = strlen(src);
int pos = time % len;
reverse_part(src, 0, pos - 1); //逆序前段
reverse_part(src, pos, len - 1); //逆序后段
reverse_part(src, 0, len - 1); //整体逆序
}