OJ 系列之常规练习题(一)

本文精选了10道编程挑战题目,涵盖了从简单的数学运算到复杂的链表操作等多个方面,旨在帮助读者提升算法思维和编程实践能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、求M的n次方最后三位

【问题描述】
正整数M 的N次方有可能是一个非常大的数字,我们只求该数字的最后三位

例1:比如输入5和3 ,5的3次方为125,则输出为125

例2:比如输入2和10 2的10次方为1024 ,则输出结果为24

例3:比如输入111和5 111的5次方为116850581551,则输出结果为551

#include <stdlib.h>
#include "oj.h"


unsigned int  GetLastThreeNumOfResult (unsigned int  m, unsigned int  n)
{   
    int i = 0;
    int result = 1;
    for(i=0;i<n;i++) {
        result = m*result%1000;
    }
    return result;
}

2、向升序单向链表中插入一个节点

需要注意一点就是第一个节点前插入节点。


#include "OJ.h"

struct ListNode {
    int       m_nKey;
    ListNode* m_pNext;
};

/*
功能: 输入一个升序单向链表和一个链表节点,向单向链表中按升序插入这个节点。
      输入为空指针的情况视为异常,另外不考虑节点值相等的情况。

输入: ListNode* pListHead  单向链表
      ListNode* pInsertNode 新插入节点

输出: ListNode* pListHead  单向链表

返回: 正常插入节点返回链表头指针,其它异常返回空指针
*/
ListNode* InsertNodeToList(ListNode* pListHead, ListNode* pInsertNode)
{
    if(!pListHead ||!pInsertNode)
        return (ListNode*)NULL;
    /*1.添加一个头结点,处理插入的节点是在第一个节点之前*/
    ListNode* dummy = (ListNode*)malloc(sizeof(ListNode));
    dummy->m_pNext = pListHead;

    ListNode* p = pListHead;
    ListNode* pre = dummy;

    while(p){
        if(p->m_nKey > pInsertNode->m_nKey){
            break;
        }
        pre = p; /*保留前一个节点*/
        p = p->m_pNext;
    }

    pInsertNode->m_pNext = p;
    pre->m_pNext = pInsertNode;

    pListHead = dummy->m_pNext;
    free(dummy);

    return pListHead;
}

3、删除链表中的重复节点、剩余节点逆序输出

解题思路:

  • 1、将链表节点的数据放入一个数组中mydata
  • 2、对这个mydata进行去重处理(本题最主要工作),剩余元素就是我们想要的数据。
  • 3、申请节点地址,逆序输出
#include <stdlib.h>
#include "oj.h"
#include <vector>
using namespace std;

typedef struct strNode {
    int data;
    strNode * pstrNext;
}strNode;

/*
功能:  输入一个不带头节点的单向链表(链表的节点数小于100),
删除链表中内容重复的节点(重复的节点全部删除),剩余的节点逆序倒排。
输入:   pstrIn: 输入一个不带头节点的单向链表  
输出:   pstrOut:删除内容重复的节点后,
逆序排列的链表(不带头节点,链表第一个节点的内存已经申请)。

返回:

示例:
输入链表的内容依次为 6,7,8,8,9,10,6
则输出链表的内容依次应该是 10,9,7

*/
void move(int *a,int index,int count)
{
    int in=index;
    /*覆盖原来的数据*/
    for(int i=0;i<count-1;i++) {
        a[in]=a[in+1];
        in++;
    }
}

int iChanProcess(strNode * pstrIn,strNode * pstrOut)
{
    if(!pstrIn||!pstrOut)
        return 0;
    /*最大节点个数为100个*/
    int mydata[100];
    strNode *pstrIntemp = pstrIn;
    int mydataLen = 0;
    /*1.取出节点的数据*/
    while(pstrIntemp) {
        mydata[mydataLen] = pstrIntemp->data;
        pstrIntemp = pstrIntemp->pstrNext;
        mydataLen ++;
    }
    int i = 0,j = 0;
    int temp = 0;
    int moveFlag = 0;
    /*2.除去相同元素*/
    for(i=0;i<mydataLen;i++) {
        temp = mydata[i];
        for(j = i+1;j<mydataLen;j++) {
            if(temp==mydata[j]) {
                move(mydata,j,mydataLen-j);
                moveFlag = 1;
                mydataLen--;
            }
        }
        if(moveFlag) {
            move(mydata,i,mydataLen-i);
            mydataLen--;
            moveFlag = 0;
        }
    }
    /*头结点地址已经申请*/
    strNode *MypstrOut=pstrOut;
    MypstrOut->data=mydata[mydataLen-1];
    /*3.逆序输出,申请节点地址*/
    for(int tep=mydataLen-2;tep>=0;tep--) {
        strNode* padd = (strNode *)malloc(sizeof(strNode));
        padd->data = mydata[tep];/*数据*/
        MypstrOut->pstrNext = padd;
        padd->pstrNext = NULL;
        MypstrOut = MypstrOut->pstrNext;
    }

    return 0;
}

/* 释放链表 */
void vFreeChan(strNode * pstrChan)
{
    strNode *p,*pstrd;
    pstrd=pstrChan;
    while(pstrd) {
        p=pstrd->pstrNext; /*保存下一个节点*/
        free(pstrd);
        pstrd=p;
    }    
    return;
}

4、二维数组的列排序

程序如下,不过时间复杂度比较高,可以使用更好的排序算法(快速排序)代替冒泡。

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

#include "oj.h"

// 功能:排列一个m行n列 大小的数组
// 输入: int * pArray 指向数组第一个元素的指针,m为行数, n为列数 ,请按第i列排列
// 输出:按第i列排序完成后的数组放到入参指定的地址中    (i的取值范围 1 - n)  
// 返回:
void RangeArray(int * pArray,unsigned int  m, 
                unsigned int  n,unsigned int  i)  
{     
    i--;  
    if (pArray == NULL || m<=0 || n<=0 || i<0 || i>=n) {  
        return;  
    } 
    int j = 0,k = 0;
    int i2 = 0;
    int aa = 0,bb = 0;
    int temp = 0;
    int nIndex = 0;
    /*前两个for目的是冒泡法排序,第三个for是列*/
    for (j=0;j<m;j++) {  /*行*/
        for (k=j+1;k<m;k++) {  
            for (i2 = i; i2<n; i2++) {  /*列*/
                aa = *(pArray+j*n+i2);  /*第j行第i2列数据*/
                bb = *(pArray+k*n+i2);  /*第j+1行第i2列数据*/
                if (*(pArray+j*n+i2) > *(pArray+k*n+i2)) {  
                    /*交换两行数据*/
                    for (nIndex=0;nIndex<n;nIndex++) {  
                        temp = pArray[j*n + nIndex];  
                        pArray[j*n + nIndex] =  pArray[k*n + nIndex];  
                        pArray[k*n + nIndex] = temp;  
                    }  
                    break;
                /*两个数相等,需要比较下一列的数据*/
                } else if (*(pArray+j*n+i2) == *(pArray+k*n+i2)) {  
                    continue;  
                /*次序正确,无需变动*/
                } else if(*(pArray+j*n+i2) < *(pArray+k*n+i2)) {  
                    break;  
                }  
            }  
        }  
    }  
}  

5、取给定正整数的指定bit位开始的指定长度的数据

startbit-bitlen+1理解为bit位从右向左数的,比如11011,startbit为3、bitlen为3,该数为101,因此原数字需要先左移到startbit-bitlen+1 = 1,移动到101最低位。

/*
Description  
取给定正整数的指定bit位开始的指定长度的数据。bit位从右向左从0开始计算。
Prototype
 unsigned int GetBitsValue(unsigned int input, unsigned int startbit,unsigned int bitlen)
Input Param 
         input      输入的整数
         startbit   需要获取的开始bit
         bitlen     需要获取的bit长度
Output Param 
         无
Return Value
         对应的bit取值
*/

unsigned int GetBitsValue(unsigned int input, unsigned int startbit, 
                                unsigned int bitlen)
{
    /*在这里实现功能*/
    if(startbit>31||bitlen>32||(bitlen>startbit))
        return -1;

    if(bitlen==0)
        return -1;
    unsigned int i = 0;
    input = input>>(startbit-bitlen+1);
    int sum = 1;
    int temp = 1;
    for(i=1;i<bitlen;i++) {
        temp  = (temp<<1);
        sum = sum + temp;
    }
    input = input&sum;

    return input;
}

6、兔子产子

假定你有一雄一雌一对刚出生的兔子,它们在长到一个月大小时开始交配,在第二月结束时,雌兔子产下另一对兔子,过了一个月后它们也开始繁殖,如此这般持续下去。每只雌兔在开始繁殖时每月都产下一对兔子,假定没有兔子死亡,在一年后总共会有多少对兔子?
在一月底,最初的一对兔子交配,但是还只有1对兔子;在二月底,雌兔产下一对兔子,共有2对兔子;在三月底,最老的雌兔产下第二对兔子,共有3对兔子;在四月底,最老的雌兔产下第三对兔子,两个月前生的雌兔产下一对兔子,共有5对兔子;……如此这般计算下去,兔子对数分别是:1, 1, 2, 3, 5, 8, 13, 21, 34, 55,89, 144, …看出规律了吗?从第3个数目开始,每个数目都是前面两个数目之和。这就是著名的斐波那契(Fibonacci)数列。

#include <stdlib.h>
#include "oj.h"
// 功能:获取第nValue1个月出生多少对兔子
// 输入: nValue1为正整数
// 输出:无
// 返回:第nValue1个月出生多少对兔子


unsigned int GetBirthRabbitNum(unsigned int  nValue1)
{
    if(nValue1==0) {
        return 0;
    }
    if(nValue1==1||nValue1==2) {
        return 1;
    }
    int sum = 1;
    int sumpre = 1;
    int i = 0;
    int result = 0;
    for(i=3;i<=nValue1;i++) {
        result = sum+sumpre;
        sumpre = sum;
        sum = result;
    }

    return result;
}

7、报文转换

/*
功能:
    将给定的报文按规则转换成另一个报文后输出。
    转换规则如下:
    报文中如果出现0x7E,转义成为2个字节0x7D 0x5E,如果出现0x7D,转义成为2个字节0x7D 0x5D。最后在报文头尾各加上一个0x7E定界。

    示例(每个字节以十六进制数表示)
    给定原始报文:1D 2B 3C 4D 5E 7E 6F 7D 7E
    转换后的报文:7E 1D 2B 3C 4D 5E 7D 5E 6F 7D 5D 7D 5E 7E

输入:
char* pInput: 给定的输入报文,内存空间由调用者申请和释放
int iLen: 给定报文的长度   
输出:
char* pOutput:转换后的报文,内存空间由调用者申请和释放
返回:
int: 成功 0, 失败 -1
*/

本文处理是先在栈中申请一个足够大的数组,长度为10000,假设报文足够,本程序不适用。

int PktTrans(char* pInput, int iLen, char* pOutput)
{

    if(pInput==NULL||*pInput=='\0'|| 
      (iLen < 0) || (iLen >= 100)||pOutput==NULL) {
        return -1;
    }
    if(iLen==0)
        return 0;

    char temp[10000];

    int i=0,j=0;

    for(i = 0;i<iLen;i++)
    {   
        if(pInput[i]==0x7E) {   
            temp[j++]=0x7D;
            temp[j++]=0x5E; 
        } else if(pInput[i]==0x7D) {
            temp[j++]=0x7D;
            temp[j++]=0x5D;
        } else {
            temp[j]=pInput[i];
            j++;
        }
    }
    temp[j]='\0';

    pOutput[0]=0x7E;

    for(int k=0;k<j;k++) {
        pOutput[k+1]=temp[k];
    }
    pOutput[j+1]=0x7E;
    pOutput[j+2]='\0';

    return 0;       
}

8、计算二进制数的0的个数

#include <stdio.h>

int bit_zero_cal(unsigned int n) 
{
    int count = 0;

    while(n) {

        if(!(n&1))
            count ++;
        n = n>>1;
    }
    printf("%d\n",count);
    return count;
}
int main()
{
    unsigned int n;
    scanf("%d",&n);
    bit_zero_cal(n);
    getchar();
}

9、简单密码破解

/*
密码是我们生活中非常重要的东东,我们的那么一点不能说的秘密就全靠它了。
哇哈哈. 接下来渊子要在密码之上再加一套密码,虽然简单但也安全。

假设渊子原来一个BBS上的密码为zvbo9441987,为了方便记忆,
他通过一种算法把这个密码变换成YUANzhi1987,这个密码是他的名字和出生年份,怎么忘都忘不了,
而且可以明目张胆地放在显眼的地方而不被别人知道真正的密码。

他是这么变换的,大家都知道手机上的字母: 
1--1, abc--2, def--3, ghi--4, jkl--5, mno--6, 
pqrs--7, tuv--8 wxyz--9, 0--0,
就这么简单,渊子把密码中出现的小写字母都变成对应的数字,数字和其他的符号都不做变换,

声明:密码中没有空格,而密码中出现的大写字母则变成小写之后往后移一位,
如:X,先变成小写,再往后移一位,不就是y了嘛,简单吧。记住,z往后移是a哦。


*/

代码实现

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

void Decoding(char *inputCodestr) 
{
    if(!inputCodestr)
        return;
    int inputCodestrLen = strlen(inputCodestr);
    int i = 0;
    while(inputCodestr[i]!='\0') {
        if(inputCodestr[i]>='A'&&inputCodestr[i]<='Y') {
            inputCodestr[i]=inputCodestr[i]+'a'-'A'+1;
        }
        else if(inputCodestr[i]=='Z') {
            inputCodestr[i]='a';
        }
        else if(inputCodestr[i]>='a'&&inputCodestr[i]<='c') {
            inputCodestr[i]='2';
        }
        else if(inputCodestr[i]>='d'&&inputCodestr[i]<='f') {
            inputCodestr[i]='3';
        }
        else if(inputCodestr[i]>='g'&&inputCodestr[i]<='i') {
            inputCodestr[i]='4';
        }
        else if(inputCodestr[i]>='j'&&inputCodestr[i]<='l') {
            inputCodestr[i]=='5';
        }
        else if(inputCodestr[i]>='m'&&inputCodestr[i]<='o') {
            inputCodestr[i]='6';
        }
        else if(inputCodestr[i]>='p'&&inputCodestr[i]<='s') {
            inputCodestr[i]='7';
        }
        else if (inputCodestr[i]>='t'&&inputCodestr[i]<='v') {
            inputCodestr[i]='8';
        }
        else if(inputCodestr[i]>='w'&&inputCodestr[i]<='z') {
            inputCodestr[i]='9';
        }
        else {
            inputCodestr[i]=inputCodestr[i];
        }
        i++;
    }

    printf("%s\n",inputCodestr);
}

int main()
{
    char inputCodestr[100];

    gets(inputCodestr);
    Decoding(inputCodestr);
    return 0;
}

10、密码验证合格程序

/*
密码要求:
1.长度超过82.包括大小写字母.数字.其它符号,以上四种至少三种
3.不能有相同长度超2的子串重复
说明:长度超过2的子串
输入:  
一组或多组长度超过2的子符串。每组占一行  
输出:  
如果符合要求输出:OK,否则输出NG

每行输出对应一组输入的结果;


样例输入:   021Abc9000
            021Abc9Abc1
            021ABC9000
            021$bc9000

样例输出: OK
          NG
          NG
          OK
*/

本题难点在于如何实现多行输入:while(scanf(“%s”,inputstr)!=EOF)
代码实现

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

void judge(char inputstr[])
{
    if(!inputstr) {
        printf("NG");
        return;
    }
    int i = 0,j = 0;
    int inputstrLen = strlen(inputstr);
/*1.条件1---长度超过8位*/
    if(inputstrLen<=8) {
        printf("NG");
        return;
    }
    int numCount = 0;
    int LowercaseLettersCount = 0;
    int CapitalLettersCount = 0;
    int OtherCharactersCount = 0;

    for (i=0;i<inputstrLen;i++) {
        if(inputstr[i]>='0' && inputstr[i]<='9')
            numCount ++;
        else if(inputstr[i]>='a' && inputstr[i]<='z')
            LowercaseLettersCount ++;
        else if(inputstr[i]>='A' && inputstr[i]<='Z')
            CapitalLettersCount ++;
        else {
            OtherCharactersCount ++;
        }
    }
/*2.条件2---至少三种字符*/
    if(numCount==0) {
        if(LowercaseLettersCount==0||CapitalLettersCount==0||OtherCharactersCount==0) {
            printf("NG");   
            return;
        }
    } else if(LowercaseLettersCount==0) {
        if(CapitalLettersCount==0||OtherCharactersCount==0) {
            printf("NG");   
            return;
        }
    } else if(CapitalLettersCount==0) {
        if(OtherCharactersCount==0) {
            printf("NG");   
            return;
        }
    }
    char inputStrtemp[2];
/*3.条件3---相同长度超2的子串重复*/
    for (i=0;i<inputstrLen-1;i++) {
        inputStrtemp[0] = inputstr[i];
        inputStrtemp[1] = inputstr[i+1];
        for(j=i+2;j<inputstrLen-1;j++) {
            if(inputstr[j]==inputStrtemp[0]&&inputstr[j+1]==inputStrtemp[1]) {
                printf("NG");   
                return;
            }

        }
    }

    printf("OK");   
}


int main()
{
    char inputstr[1024];

    while(scanf("%s",inputstr)!=EOF) {
        judge(inputstr);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

狂奔的乌龟

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

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

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

打赏作者

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

抵扣说明:

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

余额充值