【剑指offer】(17~20)

17:打印从1到最大的n位数

题目:输入数字n,按顺序打印出从1到最大的n位十进制数。比如输入3,打印出1、2、3一直到最大的3位数999。

难点:当n极大的情况,因此借助字符串模拟数字加

//方法一
void Print1ToMaxOfNDigits_1(int n)
{
    if (n <= 0)
        return;

    char *number = new char[n + 1];
    memset(number, '0', n);
    number[n] = '\0';

    while (!Increment(number)) //每次加1,溢出返回
    {
        PrintNumber(number);
    }

    delete[]number;
}

// 字符串number表示一个数字,在 number上增加1
// 如果做加法溢出,则返回true;否则为false
bool Increment(char* number)
{
    bool isOverflow = false;
    int nTakeOver = 0;  //有无溢出
    int nLength = strlen(number);

    for (int i = nLength - 1; i >= 0; i--)     //number高位存放数字低位
    {
        int nSum = number[i] - '0' + nTakeOver;
        if (i == nLength - 1)
            nSum++;      //最低位加一

        if (nSum >= 10)
        {
            if (i == 0)
                isOverflow = true;  //最高位溢出
            else
            {
                nSum -= 10;
                nTakeOver = 1;
                number[i] = '0' + nSum;
            }
        }
        else
        {
            number[i] = '0' + nSum;
            break;
        }
    }

    return isOverflow;
}
//方法二:全排列方法
void Print1ToMaxOfNDigits_2(int n)
{
    if (n <= 0)
        return;

    char* number = new char[n + 1];
    number[n] = '\0';

    for (int i = 0; i < 10; ++i)
    {
        number[0] = i + '0';
        Print1ToMaxOfNDigitsRecursively(number, n, 0);
    }

    delete[] number;
}

void Print1ToMaxOfNDigitsRecursively(char* number, int length, int index)
{
    if (index == length - 1)
    {
        PrintNumber(number);
        return;
    }

    for (int i = 0; i < 10; ++i)
    {
        number[index + 1] = i + '0';
        Print1ToMaxOfNDigitsRecursively(number, length, index + 1);
    }
}
//打印字符串
void PrintNumber(char* number)
{
    bool isBeginning0 = true;
    int nLength = strlen(number);

    for (int i = 0; i < nLength; ++i)
    {
        if (isBeginning0 && number[i] != '0')
            isBeginning0 = false;

        if (!isBeginning0)
        {
            printf("%c", number[i]);
        }
    }

    printf("\t");
}

18:删除列表的节点

题目一:在O(1)时间内删除链表节点

给定单链表的头指针和一个节点指针,定义一个函数在O(1)时间内删除该节点。

注意:考虑删除节点在链表的不同位置,链表中间,链表尾部,单一节点。

void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted)
{
    if(!pListHead || !pToBeDeleted)
        return;

    // 要删除的结点不是尾结点
    if(pToBeDeleted->m_pNext != nullptr)
    {
        ListNode* pNext = pToBeDeleted->m_pNext;  //将下一个节点复制到被删节点
        pToBeDeleted->m_nValue = pNext->m_nValue;
        pToBeDeleted->m_pNext = pNext->m_pNext;

        delete pNext;      //释放删除节点的下一个节点
        pNext = nullptr;
    }
    // 链表只有一个结点,删除头结点(也是尾结点)
    else if(*pListHead == pToBeDeleted)
    {
        delete pToBeDeleted;
        pToBeDeleted = nullptr;
        *pListHead = nullptr;
    }
    // 链表中有多个结点,删除尾结点
    else
    {
        ListNode* pNode = *pListHead;
        while(pNode->m_pNext != pToBeDeleted)
        {
            pNode = pNode->m_pNext;            
        }

        pNode->m_pNext = nullptr;
        delete pToBeDeleted;
        pToBeDeleted = nullptr;
    }
}

题目二:删除链表中重复节点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

 ListNode* deleteDuplication(ListNode* pHead)
    {
        if(pHead==NULL||pHead->next==NULL) 
            return pHead;

        ListNode* newHead=new ListNode(-1);
        newHead->next=pHead;
        ListNode* p=pHead;
        ListNode* pre=newHead;
        ListNode* next=NULL;
        while(p!=NULL&&p->next!=NULL)
        {
            next=p->next;
            if(p->val==next->val)
            {
                while(next!=NULL&&next->val==p->val)
                    next=next->next;
                pre->next=next;
                p=next;
            }
            else
            {
                pre=p;
                p=p->next;
            }
        }
        return newHead->next;

    }

19:正则表达式匹配

题目:请实现一个函数用来匹配包括’.’和 ’ * ’ 的正则表达式。模式中的字符 ‘.’ 表示任意一个字符,而 ‘* ’ 表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串”aaa”与模式”a.a”和”ab * ac a”匹配,但是与”aa.a”和”ab a”均不匹配

bool match(const char* str, const char* pattern)
{
    if(str == nullptr || pattern == nullptr)
        return false;

    return matchCore(str, pattern);
}

bool matchCore(const char* str, const char* pattern)
{
    if(*str == '\0' && *pattern == '\0')
        return true;

    if(*str != '\0' && *pattern == '\0')
        return false;

    if(*(pattern + 1) == '*')
    {
        if(*pattern == *str || (*pattern == '.' && *str != '\0'))
            // 进入有限状态机的下一个状态
            return matchCore(str + 1, pattern + 2)
            // 继续留在有限状态机的当前状态 
            || matchCore(str + 1, pattern)
            // 略过一个'*' 
            || matchCore(str, pattern + 2);
        else
            // 略过一个'*'
            return matchCore(str, pattern + 2);
    }

    if(*str == *pattern || (*pattern == '.' && *str != '\0'))
        return matchCore(str + 1, pattern + 1);

    return false;
}

20:表示数值的字符串

题目:请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串”+100”,”5e2”,”-123”,”3.1416”和”-1E-16”都表示数值。 但是”12e”,”1a3.14”,”1.2.3”,”+-5”和”12e+4.3”都不是。

 // 数字的格式可以用A[.[B]][e|EC]或者.B[e|EC]表示,其中A和C都是
// 整数(可以有正负号,也可以没有),而B是一个无符号整数
bool isNumeric(const char* str)
{
    if(str == nullptr)
        return false;

    bool numeric = scanInteger(&str);

    // 如果出现'.',接下来是数字的小数部分
    if(*str == '.')
    {
        ++str;

        // 下面一行代码用||的原因:
        // 1. 小数可以没有整数部分,例如.123等于0.123;
        // 2. 小数点后面可以没有数字,例如233.等于233.0;
        // 3. 当然小数点前面和后面可以有数字,例如233.666
        numeric = scanUnsignedInteger(&str) || numeric;
    }

    // 如果出现'e'或者'E',接下来跟着的是数字的指数部分
    if(*str == 'e' || *str == 'E')
    {
        ++str;

        // 下面一行代码用&&的原因:
        // 1. 当e或E前面没有数字时,整个字符串不能表示数字,例如.e1、e1;
        // 2. 当e或E后面没有整数时,整个字符串不能表示数字,例如12e、12e+5.4
        numeric = numeric && scanInteger(&str);
    }

    return numeric && *str == '\0';
}

bool scanUnsignedInteger(const char** str)
{
    const char* before = *str;
    while(**str != '\0' && **str >= '0' && **str <= '9')
        ++(*str);

    // 当str中存在若干0-9的数字时,返回true
    return *str > before;
}

// 整数的格式可以用[+|-]B表示, 其中B为无符号整数
bool scanInteger(const char** str)
{
    if(**str == '+' || **str == '-')
        ++(*str);
    return scanUnsignedInteger(str);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值