牛客剑指offer刷题记录(六)

本文解析了几道经典的算法题目,包括连续子数组最大和、找出数组中首次出现的字符等,并提供了解决方案,如动态规划法、筛选法及哈希表的应用。

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


连续子数组最大和

动态规划的题目,定义dp(i)是以第i个数字结尾的子数组的最大和,那么有如下动态规划方程:
dp(i)=num(i),i=0dp(i1)<=0
dp(i)=dp(i1)+num(i),i>0dp(i1)>0

class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {
        if (array.size() == 0)
            return 0;
        vector<int>dp(array.size());
        int cur = numeric_limits<int>::min();
        for (int i = 0; i < array.size(); ++i)
        {
            if (i == 0 || dp[i-1] <= 0)
                dp[i] = array[i];
            if (i>0 && dp[i-1] > 0)
                dp[i] = dp[i - 1] + array[i];
            if (dp[i] > cur)
                cur = dp[i];
        }
        return cur;
    }
};

当然也可以用局部最优和全局最优的方式来做,局部最优保证以当前数字结尾,的最大值那么有:
local(i)=max(local(i1)+num(i),num(i))
然后求全局最优:
global(i)=max(local(i),global(i1))

class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {
        vector<int>a;
        a.swap(array);
        vector<int>local(a.size());
        vector<int>global(a.size());
        local[0] = a[0];
        global[0] = a[0];
        for (int i = 1; i<a.size(); ++i)
        {
            local[i] = max(a[i], local[i - 1] + a[i]);
            global[i] = max(local[i], global[i - 1]);
        }
        return global[a.size() - 1];
    }
};

从1到n整数中1出现的次数

剑指offer上面讲的不清楚。
参考:http://blog.youkuaiyun.com/yi_afly/article/details/52012593

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
    {
        if (n < 0)
            return 0;
        int count = 0;
        int weight = 0;
        int round = 0;
        int base = 1;
        int origin = n;

        while (n > 0)
        {
            weight = n % 10;
            round = n / 10;
            if (weight == 1)
            {
                count += round*base;
                count += ((origin%base) + 1);
            }
            else if (weight == 0)
            {
                count += round*base;
            }
            else
            {
                count += round*base;
                count += base;
            }
            base *= 10;
            n /= 10;
        }
        return count;
    }
};

把数组排成最小的数

希望较高位出现较小的数,需要找到一个合适的排序规则,能够在这些全排列里面筛选出最小的数。直接排序肯定是不行的,比如12,333,9直接排序后9出现在最高位,是不符合要求的。

给出两个数字a和b需要判断哪个数在前面就要比较ab和ba

整型的拼接先转成string,然后再比较a+b和b+a的大小

把上述规则写成比较函数,利用sort很容易:

class comp{
public:
    bool operator()(string a, string b)
    {
        return a + b < b + a;
    }
};
class Solution {
public:
    string PrintMinNumber(vector<int> numbers) {
        if (numbers.size() == 0)
            return string();
        vector<string>n; 
        n.reserve(numbers.size());
        for(auto num : numbers)
        {
            n.push_back(to_string(num));
        }
        sort(n.begin(), n.end(), comp());
        string r;
        for (auto i : n)
        {
            r += i;
        }
        return r;
    }
};

丑数

2、3、5为因数,可以写一个判断丑数的代码:

int judgeUgly(int n)
    {
        while (n % 2==0)
            n /= 2;
        while (n % 3 == 0)
            n /= 3;
        while (n % 5 == 0)
            n /= 5;
        return (n == 1) ? true : false;
    }

然后利用这个函数,统计n个丑数,这个办法效率较低原因在于每个数字都要进行判断一遍:

class Solution {
private:
    bool judgeUgly(int n)
    {
        while (n % 2==0)
            n /= 2;
        while (n % 3 == 0)
            n /= 3;
        while (n % 5 == 0)
            n /= 5;
        return (n == 1) ? true : false;
    }
public:
    int GetUglyNumber_Solution(int index) {
        int i = 1;
        int count = 0;
        while (true)
        {
            if (judgeUgly(i))
            {
                ++count;
            }
            if (count == index)
                break;
            ++i;
        }
        return i;
    }
};

最终超时。

效率更高的办法叫做筛选法:
首先需要一个容器,假定里面就是存放所有1-Index的丑数,第一个个丑数是1,后面所有的丑数都是前面的丑数乘上2、3、5得来的。

class Solution {
public:
    int GetUglyNumber_Solution(int index) {
        vector<int>ugly(index);
        ugly[0] = 1;
        int i, j, k;
        i = j = k = 0;
        for (int count = 1; count < index; ++count)
        {
            ugly[count] = min(ugly[i] * 2, min(ugly[j] * 3, ugly[k] * 5));
            if (ugly[count] == ugly[i] * 2)++i;
            if (ugly[count] == ugly[j] * 3)++j;
            if (ugly[count] == ugly[k] * 5)++k;
        }
        return ugly[index - 1];

    }
};

第一个只出现一次的字符

hash是最简单的解法了:

class Solution {
public:
    int FirstNotRepeatingChar(string str) {
        unordered_map<char,int>m;
        for(int i=0;i<str.size();++i){
            ++m[str[i]];
        }
        for(int i=0;i<str.size();++i){
            if(m[str[i]]==1){
                return i;
            }
        }
        return -1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值