春招刷题笔记-剑指offer-代码的完整性

代码的完整性

数值的整数次方

题目描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

class Solution {
public:
    double Power(double base, int exponent) {
        double result = 0;
        
        //  指数为0,返回1
        if (exponent == 0)
            result = 1;
        result = 1;
        int temp = exponent < 0 ? -exponent : exponent;
        for (int i = 0; i < temp; i++)
            result = result * base;
        if (exponent < 0) {
            result = 1.0 / result;
        }
        return result;
    }
};

/*  更严谨的解法并且使用了幂函数的性质,可以在O(logn)的时间内求解出来:
a^n = a^(n/2) * a^(n/2)         n为偶数时;
a^n = a^(n/2) * a^(n/2) +1      n为奇数时。
*/
class Solution {
public:
    double Power(double base, int exponent) {
        double result = 0;
        
        //  底数为0,并且这时候的指数小于0,会造成0在分母上的情况
        if ((base >= -__DBL_EPSILON__ && base <= __DBL_EPSILON__) && exponent < 0)
            return 0;
        
        unsigned int exponent_ = exponent > 0 ? (unsigned int)(exponent) : (unsigned int)(-exponent);
        result = PowerWithUnsignedExponent(base, exponent_);
        if (exponent < 0)
            result = 1.0 / result;
        return result;
    }

    double PowerWithUnsignedExponent(double base, unsigned int exponent) {
        if (exponent == 0)
            return 1;
        if (exponent == 1)
            return base;
        double result = PowerWithUnsignedExponent(base, exponent >> 1);

        result *= result;

        //  最好采用位运算来判断最后一位是不是1,
        //  计算机中位运算的速度比算数运算的快
        //if (exponent % 2 == 1)
        if (exponent & 0x1 == 1)
            result *= base;
        
        return result;

    }
};

打印1到最大的n位数

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

思路分析: 本道题目需要注意的陷阱是大数的问题,如果给出的n比较大,很有可能会超出计算机能表示的最大的整数的范围,所以此题需要借助一个字符数组来模拟整数,字符数组的大小为n+1,最后一位number[n]用来保存数组的结束标志’\0’,采用全排列的方式来输出。

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++) {
        //  第一个数字分别是从0 ~ 9
        number[0] = i + '0';
        Print1ToMaxOfNDigitsRecursively(number, n, 0);
    }
}

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);
    }
}

//  字符串number表示一个数字,数字有若干个0开头
//  打印出这个数字,并忽略开头的0
void PrintNumber(char* number) {
    bool isBegining = true;
    int length = strlen(number);
    for (int i = 0; i < length; i++) {
        if (isBegining && number[i] != '0')
            isBegining = false;
        if (!isBegining) {
            printf("%c", number[i]);
        }
    }
    printf("\t");
}

在O(1)时间删除链表结点

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

思路分析: 本题需要注意的是题目给出的用O(1)的时间删除一个节点,另外需要注意的是如果链表只有一个节点的话,需要把头结点设置为空;如果要删除的节点是尾节点需要从头开始遍历到尾节点的前一个节点;如果要删除的节点在中间位置,那么交换要删除的节点和下一个节点的值,再删除下一个节点就OK了。

struct ListNode {
    int data;
    struct ListNode* next;
};

void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted) {
    //  如果头节点为空或者指定的节点为空,那么直接返回
    if (pListHead == nullptr || pToBeDeleted == nullptr)
        return;

    //  如果指定的节点就是头结点,并且链表只有一个节点
    if (pToBeDeleted == *pListHead && pToBeDeleted -> next == nullptr) {
        delete pToBeDeleted;
        pToBeDeleted = nullptr;
        *pListHead = nullptr;
    } else if (pToBeDeleted -> next == nullptr) {
        //  如果指定的节点是尾节点,那么从头开始遍历,删除尾节点
        ListNode* temp = nullptr;
        temp = *pListHead;
        while (temp && temp -> next != pToBeDeleted)
            temp = temp -> next;
        if (temp -> next == pToBeDeleted) {
            //  确保一定能在链表中找到指定的节点
            temp -> next = nullptr;
            delete pToBeDeleted;
        }
    } else {
        //  如果指定的节点是链表中间的某一个节点
        ListNode* temp = pToBeDeleted -> next;
        pToBeDeleted -> data = temp -> data;
        pToBeDeleted -> next = temp -> next;
        delete temp;
        temp = nullptr;
    }    
}

删除链表中的重复节点

题目描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5.

思路分析:
借助三个指针nodepre,node,和nodenext。nodepre指向的是没有重复的那部分链表的尾部,node和nodenext两个指针的偏移来标记值相同的节点,其中node指向的是有重复数字的最后一个节点,nodenext指向的是node的下一个节点,在删除节点的时候,将nodepre的next指针指向nodenext,node的next指针置为空,就可以删除从nodepre的下一个节点开始到node指向的节点之间的所有重复的节点,删除完成之后,将nodepre指针不变,node指针置为nodenext,nodenext为node的下一个节点。以此类推。注意nodepre的偏移只发生在没有重复节点的时候,如果有重复节点,并且要删除重复节点那么就不会有nodepre指针的偏移。

注意:
(1)本题需要注意的是指针的溢出,因为引入了nodepre,node,nodenext三个指针来判断处理,所以在nodenext这个地方很容易就出现指针的溢出;
(2)引入一个节点phead作为头结点,使得头结点的操作和其余所有节点的操作是一样的;

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead) {
        //  链表为空或者链表只有一个节点
        if  (pHead == nullptr || pHead -> next == nullptr)
            return pHead;
        
        //  引入一个节点作为头节点,使得pHead指向的节点的
        //  操作和其余的节点的操作是一样的
        ListNode* phead = new ListNode(0);
        phead -> next = pHead;

        ListNode* nodepre = phead;
        ListNode* node = pHead;
        ListNode* nodenext = nullptr;
        if (node != nullptr)
            nodenext = node -> next;
        while (node) {
            if (nodenext && node -> val == nodenext -> val) {
                while (nodenext && node && nodenext -> val == node -> val) {
                    //寻找重复的节点
                    node = node -> next;
                    nodenext = nodenext -> next;
                }
                //  从nodepre下一个位置 开始到node位置的节点都是重复的节点
                ListNode* temp = nodepre -> next;
                nodepre -> next = nodenext;
                node -> next = nullptr;
                while (temp != nullptr) {
                    node = temp ;
                    temp = temp -> next;
                    delete node;
                }
                temp = nullptr;
                node = nodepre;
            }
            nodepre = node;
            node = nodenext;
            if (node != nullptr)
                nodenext = node -> next;
        }
        pHead = phead -> next;
        delete phead;
        return pHead;
    }
};

正则表达式的匹配

题目描述: 请实现一个函数用来匹配包含’.‘和’‘的正则表达式。模式中的字符’.’
表示任意一个字符,而’
'表示它前面的字符可以出现任意次(含0次)。在本题
中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"
和"abaca"匹配,但与"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) == '*') {
        /*  模式的第二个字符是*的时候,有两种选择
        第一种:匹配串和模式串的第一个字符是匹配的:这种情况下,有三种往下走的方式
        ![这里写图片描述](https://img-blog.csdn.net/20171007084510213?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWluZ3lm/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
        */
        if (*str == *pattern 
            || (*str != '\0' && *pattern == '.')) {
            return matchCore(str + 1, pattern + 2) 
                    || matchCore(str + 1, pattern) || matchCore(str, pattern + 2);
        } else {
            matchCore(str, pattern + 2);
        }
    }

    if ((*str == *pattern)) || (*str != '\0' && *pattern == '.')) {
        return matchCore(str + 1, pattern + 1);
    }
    return false;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2023年3月11日,美团春季招聘笔试中共包含五道编程题目。以下是对每道题目的简要说明: 1. 题目一:这道题目要求解决一个数字统计的问题。可能涉及到的知识点包括数据结构、循环和条件判断等。解决问题的思路可能是使用字典等数据结构来保存统计结果,并使用循环逐个读取输入数据并进行统计。 2. 题目二:这道题目可能是一个字符串处理的问题。需要使用字符串的方法进行操作,如提取、拼接、查找和替换等。可能的解决思路包括使用正则表达式、切片和遍历等。 3. 题目三:这道题目可能涉及到算法和数据结构的知识。可能是一道涉及到数组、链表、树等数据结构的问题。解决思路可能包括遍历、递归、搜索和排序等。 4. 题目四:这道题目可能是一个动态规划的问题。需要根据给定的条件和规则,通过动态规划的方式求解问题。解决思路包括定义状态和转移方程,使用递推或记忆化搜索进行求解。 5. 题目五:这道题目可能是一个图论或网络问题。需要根据给定的图或网络结构,解决一个相关的问题。可能涉及到广度优先搜索、深度优先搜索、最短路径等知识。解决思路可能包括使用图或网络的相关算法进行求解。 以上只是对这五道编程题目的一些可能情况进行的简要描述,具体的题目内容可能会有所不同。希望这些信息能对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值