剑指offer-数学

题目一:

输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。

输出描述: 对应每个测试案例,输出两个数,小的先输出。

解题思路:

数列满足递增,设两个头尾两个指针i和j,

若ai + aj == sum,就是答案(相差越远乘积越小)

若ai + aj > sum,aj肯定不是答案之一(前面已得出 i 前面的数已是不可能),j -= 1

若ai + aj < sum,ai肯定不是答案之一(前面已得出 j 后面的数已是不可能),i += 1

时间复杂度O(n)

class Solution {
public:
    vector<int> FindNumbersWithSum(vector<int> array,int sum) {
        int i=0,j=array.size()-1;
        vector<int> res;
        while(i<j)
        {
            if(array[i]+array[j]==sum)
            {
                res.push_back(array[i]);
                res.push_back(array[j]);
                break;
            }
            else if(array[i]+array[j]<sum)
                i++;
            else
                j--;
        }
        return res;
    }
};

题目二:

汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

解法很多;

方案一:

class Solution {
public:
    string LeftRotateString(string str, int n) {
        if(str.size()==0) return str;
        int rn=n%str.size();
        str.insert(str.end(),str.begin(),str.begin()+rn);
        str.erase(str.begin(),str.begin()+rn);
        return str;
    }
};

方案二:

class Solution {
public:
    string LeftRotateString(string str, int n) {
        int len = str.length();
        if(len == 0) return str;
        n = n % len;
        str += str;
        return str.substr(n, len);
    }
};

方案三:

假设字符串abcdef,n=3,设X=abc,Y=def,所以字符串可以表示成XY,如题干,问如何求得YX。假设X的翻转为XT,XT=cba,同理YT=fed,那么YX=(XTYT)T,三次翻转后可得结果。

class Solution {
public:
    string LeftRotateString(string str, int n) 
    {
      int len = str.size();
        if(len == 0) return str;
        n %= len;
        for(int i = 0, j = n - 1; i < j; ++i, --j) swap(str[i], str[j]);
        for(int i = n, j = len - 1; i < j; ++i, --j) swap(str[i], str[j]);
        for(int i = 0, j = len - 1; i < j; ++i, --j) swap(str[i], str[j]);
        return str;
    }
};

方案四:

    class Solution {
public:
    void fun(string &s,int start,int end)
    {
        char temp;
        while(start<end)
        {
            temp=s[start];
            s[start]=s[end];
            s[end]=temp;
            start++;
            end--;
        }
    }
    string LeftRotateString(string str, int n) {
        int len=str.length();
        if(0==len || 0==n)
            return str;
        string &temp=str;
        fun(temp,0,n-1);
        fun(temp,n,len-1);
        fun(temp,0,len-1);
        return str;
    }
};

方案五:

class Solution {
public:
    string LeftRotateString(string str, int n) {
        int len = str.length();
        if(len == 0) return str;
        n = n % len;
        reverse(str.begin(),str.begin()+n);
        reverse(str.begin()+n,str.end());
        reverse(str.begin(),str.end());
        return str;
    }
};

 

题目三:

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

三种解法:

方案一:

class Solution {
public:
    string ReverseSentence(string str) {
        auto first=str.begin();
        auto second=str.begin();
        for(;second!=str.end();second++)
        {
            if(*second==' ') 
            {
                reverse(first,second);
                first=second+1;
            }
        }
        reverse(first,second);
        reverse(str.begin(),str.end());
        return str;
    }
};

方案二:

class Solution {
public:
    void ReverseWord(string &str, int s, int e)
    {
        while(s < e)
            swap(str[s++], str[e--]);
    }
    string ReverseSentence(string str) {
        ReverseWord(str, 0, str.size() - 1); //先整体翻转
        int s = 0, e = 0;
        int i = 0;
        while(i < str.size())
        {
            while(i < str.size() && str[i] == ' ') //空格跳过
                i++;
            e = s = i; //记录单词的第一个字符的位置
            while(i < str.size() && str[i] != ' ') //不是空格 找单词最后一个字符的位置
            {
                i++;
                e++;
            }
            ReverseWord(str, s, e - 1); //局部翻转
        }
        return str;
    }
};

 方案三:

class Solution {
public:
    string ReverseSentence(string str) {
        string res = "", tmp = "";
        for(unsigned int i = 0; i < str.size(); ++i){
            if(str[i] == ' ') res = " " + tmp + res, tmp = "";
            else tmp += str[i];
        }
        if(tmp.size()) res = tmp + res;
        return res;
    }
}; 

 

题目四:

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。

方案一:

1、排序 

2、计算所有相邻数字间隔总数 

3、计算0的个数 

4、如果第2、3步相等,就是顺子 

5、如果出现对子,则不是顺子

class Solution {
public:
    bool IsContinuous( vector<int> numbers ) {
        if(numbers.size()!=5) return false;
        sort(numbers.begin(),numbers.end());
        int C0=count(numbers.begin(),numbers.end(),0);
        for(int i=C0+1;i<numbers.size();i++)
        {
            if(numbers[i]==numbers[i-1]) return false;
            else
            {
                if(numbers[i]-numbers[i-1]-1>C0) return false;
                else
                    C0-=numbers[i]-numbers[i-1]-1;
            }
        }
        return true;
    }
};
class Solution {
public:
    bool IsContinuous( vector<int> numbers ) {
        if(numbers.size()!=5) return false;
        int numOfZero = 0;
        int numOfInterval = 0;
        sort(numbers.begin(),numbers.end());
        for(int i=0;i<numbers.size()-1;i++)
        {
            // 计算癞子数量
            if (numbers[i] == 0) {
                numOfZero++;
                continue;
            }
            // 对子,直接返回
            if (numbers[i] == numbers[i + 1]) 
                return false;
            numOfInterval += numbers[i + 1] - numbers[i] - 1;
        }
        if (numOfZero >= numOfInterval) {
            return true;
        }
        return false;
    }
};

方案二:

max 记录 最大值
min 记录  最小值

满足条件 1 max - min <5
               2 除0外没有重复的数字(牌)
               3 数组长度 为5 

class Solution {
public:
    bool IsContinuous( vector<int> numbers ) {
        if(numbers.size()!=5) return false;
        int* dp=new int[14];
        int max=-1;
        int min=14;
        for(int i=0;i<numbers.size();i++)
        {
            if(numbers[i]==0) continue;
            dp[numbers[i]]++;
            if(dp[numbers[i]]>1) return false;
            if(numbers[i] >max)
                max = numbers[i];  
            if(numbers[i] <min)
                min = numbers[i];
        }
        if(max-min>=5) return false;
        return true;
    }
};

参考:https://www.nowcoder.com/profile/3765387/codeBookDetail?submissionId=18859853

 

 

 

 

 

posted @ 2019-08-14 22:36  DH_HUSTer  阅读(13)  评论(0编辑  收藏  举报