每日做题之剑指offer(八)

10 篇文章 0 订阅
9 篇文章 0 订阅

1.翻转单词序列

时间限制:1秒 空间限制:32768K 热度指数:197013

本题知识点: 字符串

题目描述

牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

解题思路:

  • 第一步翻转句子中的所有字符,将“I am a student.”翻转后变为“.tneduts a ma I”
  • 第二步就是翻转每个单词中的字符顺序,就可以得到“ students. a am I ”
class Solution {
public:
    string ReverseSentence(string str) {
         if("" == str)
            return "";
        
        int left = 0;
        for(int i = 0;i < str.size(); ++i){
            if(str[i]==' ' || i==str.size()-1){
                if(i == str.size()-1)
                    i++;
                reverse(str.begin() + left, str.begin() + i);
                left = i + 1;
            }
        }
        reverse(str.begin(),str.end());
        return  str;
    }
};

2.扑克牌顺子

时间限制:1秒 空间限制:32768K 热度指数:113417

本题知识点: 字符串

题目描述

LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。

解题思路:

  • 首先将数组进行排序
  • 然后统计数组中0的个数
  • 最后统计排序之后的数组中相邻数字的空缺总数,如果空缺总数小于或者等于0的个数,那么这个数组就是连续的;否则就不是连续的
  • 注意:如果数组中的非0数字重复出现,那么该数组一定不是连续的
class Solution {
public:
    bool IsContinuous( vector<int> numbers ) {
        int len = numbers.size();
        
        if(len <= 0)
            return false;
        
        std::sort(numbers.begin(), numbers.end());
        
        int countZero = 0;
        int countGap = 0;
        
        //统计数组中的0的个数
        for(int i = 0; i < len && numbers[i] == 0; ++i)
            ++countZero;
        
        
        //统计数组中空缺的个数
        int small = countZero;
        int big = small + 1;
        while(big < len)
        {
            if(numbers[small] == numbers[big])
                return false;
            countGap += numbers[big] - numbers[small] - 1;
            small = big;
            ++big;
        }
        return (countGap > countZero) ? false : true;
    }
};

3.孩子们的游戏(圆圈中最后剩下的数)

时间限制:1秒 空间限制:32768K 热度指数:109768

本题知识点: 模拟

题目描述

每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)

class Solution {
public:
    int LastRemaining_Solution(int n, int m)
    {
        if(n < 1 || m < 1)
            return -1;
        
        int i = 0;
        list<int> numbers;
        for( ; i < n; ++i)
        {
            numbers.push_back(i);
        }
        
        list<int>::iterator current = numbers.begin();
        while(numbers.size() > 1)
        {
            for(int i = 1; i < m; ++i)
            {
                current++;
                if(current == numbers.end())
                    current = numbers.begin();
            }
            
            list<int>::iterator next = ++current;
            if(next == numbers.end())
                next = numbers.begin();
            
            --current;
            numbers.erase(current);
            current = next;
        }
        return *(current);
    }
};

 

4.求1+2+3+....+n

时间限制:1秒 空间限制:32768K 热度指数:112830

题目描述

求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

解题思路:

思路一:利用构造函数求解

  • 围绕循环做文章,循环只是让相同的代码重复执行n次
  • 我们可以定义一个类,然后创建n个该类型的实例,那么这个类型的构造函数将会被调用n次
class Temp{
public:
    Temp(){
        ++N;
        Sum += N;
    }
    static void Reset()
    {
        N = 0;
        Sum = 0;
    }
    static int GetSum()
    {
        return Sum;
    }
 private:
    static int N;
    static int Sum;
};

int Temp::N=0;
int Temp::Sum=0;

class Solution {
public:
    int Sum_Solution(int n) {
        Temp::Reset();
        
        Temp *a = new Temp[n];
        delete[] a;
        a = NULL;
        return Temp::GetSum();
    }
};

思路二:利用虚函数求解

  • 围绕递归做文章,既然不能咋一个函数中判断是不是应该终止递归,那么可以定义两个函数
  • 一个函数充当递归函数的角色,另一个函数处理终止递归的情况
  • 可以用布尔变量,true(1)嗲用第一个函数,值为false(1)调用第二个函数
  • 关键是要将数值变量转化成布尔值,!!n转换成true, !n转换成false;如果是0取反正好相反
  • 用虚函数可以实现函数的选择,当n不为0时,嗲用函数B::Sum;当n为0,调用函数A::Sum
class A{
public:
    virtual int sum_solution(int N){
        return 0;
    }
};
 
 A* p[2];
 
class B:public A{
public:
    virtual int sum_solution(int N){
        return p[!!N]->sum_solution(N-1)+N;
    }
};
 

class Solution {
public:
    int Sum_Solution(int n) {
          A a;
        B b;
        p[0]=&a;
        p[1]=&b;
        return p[!!n]->sum_solution(n);
    }
};

思路三:利用公式n(n+1)/2

class Solution {
public:
    int Sum_Solution(int n) {
        return n*(n+1)/2;
    }
};

5.不用加减乘除做加法

时间限制:1秒 空间限制:32768K 热度指数:70976

题目描述

写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

解题思路:

  • 以5和17相加为例,5的二进制位0101, 17的二进制为0001 0001.先试着把计算分成三步来计算
  • 第一步,将各位依次相加但不计算进位,得到的结果是0001 0100(最后一位相加的结果是二进制的0000 0010,这一步不计进位)
  • 第二步,记下进位,进位结果是0000 0010
  • 第三步,将前面两步的结果进行相加,得到的结果就是0001 0110,转换成十进制正好是22
  • 所以接下来就是想办法将上述步骤中的加法转换成位运算
  • 第一步不考虑进位然后对每一位进行相加。1+0=1,0+1=1,0+0=0,1+1=0,可以看出这和异或运算一样
  • 第二步产生进位, 对0+1,1+0,0+0的结果都不会产生进位,只有1+1会产生进位,可以看出这和按位与运算一样。先将两个数按位与,然后向左移动一位即为进位
  • 第三步就是将前面两个步骤产生的结果进行相加,相加的过程仍然是重复前面的两步,直到不产生进位为止
class Solution {
public:
    int Add(int num1, int num2)
    {
        /*
    首先看十进制是如何做的: 5+7=12,三步走
    第一步:相加各位的值,不算进位,得到2。
    第二步:计算进位值,得到10. 如果这一步的进位值为0,那么第一步得到的值就是最终结果。
    第三步:重复上述两步,只是相加的值变成上述两步的得到的结果2和10,得到12。
    同样我们可以用三步走的方式计算二进制值相加: 5-101,7-111 第一步:相加各位的值,不算进位,
    得到010,二进制每位相加就相当于各位做异或操作,101^111。
    第二步:计算进位值,得到1010,相当于各位做与操作得到101,再向左移一位得到1010,(101&111)<<1。
    第三步重复上述两步, 各位相加 010^1010=1000,进位值为100=(010&1010)<<1。
     继续重复上述两步:1000^100 = 1100,进位值为0,跳出循环,1100为最终结果 */
         int sum, carray;
        do{
            sum = num1 ^ num2;
            carray = (num1&num2)<<1;
            num1 = sum;
            num2 = carray;
        }while(num2 != 0);
        
        return num1;
    }
};

6.把字符串转换成整数

时间限制:1秒 空间限制:32768K 热度指数:121578本题知识点: 字符串

题目描述

将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。

输入描述:

输入一个字符串,包括数字字母符号,可以为空

输出描述:

如果是合法的数值表达则返回该数字,否则返回0

示例1

输入

复制

+2147483647
    1a33

输出

复制

2147483647
    0
class Solution {
public:
        enum Status {kValid = 0, kInvalid};
    int g_nStatus = kValid;
     
    long long StrToIntCore(const char* digit, bool minus){
        long long num = 0;
         
        while(*digit != '\0'){
            if(*digit >= '0' && *digit <= '9'){
                int flag = minus ? -1 : 1;
                num = num * 10 + flag * (*digit - '0');
                 
                if((!minus && num > 0x7FFFFFFF) || (minus && num < (signed int)0x80000000)){
                    num = 0;
                    break;
                }
                digit++;
            }
            else{
                num = 0;
                break;
            }
        }
        if(*digit == '\0'){
            g_nStatus = kValid;
        }
        return num;
    }
    
    int StrToInt(string str) {
        g_nStatus = kInvalid;
        long long num = 0;
        int length = str.length();
        const char* cstr = str.c_str();
        if(cstr != NULL && *cstr != '\0'){
            bool minus = false;
            if(*cstr == '+')
                cstr++;
            else if(*cstr == '-'){
                cstr++;
                minus = true;
            }
             
            if(*cstr != '\0'){
                num = StrToIntCore(cstr, minus);
            }
        }
        return (int)num;
    
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值