剑指offer笔试题31~35

本文探讨了连续子数组的最大和问题及1到n整数中1出现次数的问题,提出了高效的算法解决方案,并介绍了如何将数组排列成最小数字的方法。

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

31.连续子数组的最大和

题目表述: 输入一个整形数组,有正数也有负数。数组中一个或多个连续的整数构成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。 {6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。
简单的思路一: 枚举出所有的子数组,时间复杂度为O(n*n)

class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) 
    {
        if(array.empty())
            return 0;
        int max = array[0];
        int result = 0;
        for(int i=0; i<array.size(); ++i)
        {
            result = 0;
            for(int j=i; j<array.size(); ++j)
            {
                result += array[j];
                if(max < result)
                    max = result;
            }
        }
        return max;
    }
};

改善的思路二:
(1) 当前和curSum为负数:无论接下来的array[i]是正或负,array[i]>curSum必定成立。
(2) 随时更最大值。

class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) 
    {
        if(array.empty())
            return 0;
        int maxSum = array[0];
        int curSum = array[0];
        for(int i=1; i<array.size(); ++i)
        {
            curSum = max(curSum+array[i],array[i]);//情形(1)
            maxSum = max(curSum,maxSum);
        }
        return maxSum;
    }
};

32.整数中1出现的次数(从1到n整数中出现的次数)

题目表述: 求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
简单的思路一: 两次for循环的方法肯定不行。
改善的思路二: 某一位中1的个数受到它本身curNum,前面的所有高位preNume,后面的所有低位nextNum三者的共同影响。==例如
(1) 百位 等于零:只受低位的影响: n=13014 1的个数为 13*1000
(2) 百位 大于一:只受高位的影响: n=13214 *1的个数为 (13+1)1000
(3) 百位 等于一:同时受高位和低位的影响: n=13114 1的个数为 13*1000+14+1
(4) 剩下的工作就是找到各个位的数值

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
    {
        /*
            分别计算个位,十位,百位,千位...上的1的个数
            计算每个位时,需要分三种情况
            1.该为为0,个数由他的高位决定
            2.该为为1,个数由它的高位和低位共同决定
            3.该位大于1,个数又高位决定
        */
        if (n<=0)
            return 0;
        int countOf1 = 0;
        int times = 1;//个位开始
        int curNum=0,preNum=0,nextNum=0;
        while((n/times)!=0)
        {
            curNum = (n/times)%10;        //当前为
            preNum = n/(times*10);        //高位
            nextNum= n-(n/times)*times;    //低位
            if(curNum==0)
                countOf1 += preNum*times;
            else if(curNum==1)
                countOf1 += preNum*times+nextNum+1;
            else
                countOf1 += (preNum+1)*times;
            times *= 10;//进位
        }
        return countOf1;
    }
};

牛逼的思路三:

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
    {
        int count = 0;
        int i = 1;//个位开始
        for(int i=1; i<=n; i*=10)
        {
            int preNum = n / i;
            int nextNum= n % i;
            //这一步是真的非常牛逼,能通过补8来分析该位为0,1,>1的情况
            // =0或1时,补8,成9,不会对除10产生影响
            // >1时,补9,高位进一
            //后面判断低位的影响
            count += (preNum+8)/10*i + (preNum%10==1)*(nextNum+1);
        }
        return count;
    }
};

32.把数组排成最小的数

题目表述: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
思路:
(1) 两个整型数字组合后可能出现大数,因此转换到字符形式
(2) 因为是组合出最小数,那我们可以将所有的数字按“从小到大”排列
(3) 这里我们需要重新定义我们需要的“大小”关系
(4) 组合a=3和b=32两个数字有 s1=“332”,s2=“323”
(5) 对于我们来说 s1>s2 因此我们 定为 a>b
(6) 排序之后只需要将所有的数字按顺序转换为字符进行拼接即可

class Solution {
public:
    string PrintMinNumber(vector<int> numbers) 
    {
        /*
            两个整型数字组合后可能出现大数,因此转换到字符形式
            因为是组合出最小数,那我们可以将所有的数字按“从小到大”排列
            这里我们需要重新定义我们需要的“大小”关系
            组合a=3和b=32两个数字有 s1=“332”,s2=“323” 
            对于我们来说 s1>s2 因此我们 定为 a>b
            排序之后只需要将所有的数字按顺序转换为字符进行拼接即可
        */
        string result="";
        if(numbers.empty())
            return result;
        sort(numbers.begin(),numbers.end(),compara);
        for(int i=0; i<numbers.size(); ++i)
            result += to_string(numbers[i]);
        return result;
    }
       /*
        sort中的比较函数compare要声明为静态成员函数或全局函数,
        不能作为普通成员函数,否则会报错。因为:非静态成员函数是
        依赖于具体对象的,而std :: sort这类函数是全局的,因此无
        法在排序中调用非静态成员函数。静态成员函数或者全局函数是不
        依赖于具体对象的,可以独立访问,无须创建任何对象实例就可访
        问。同时静态成员函数不可以调用类的非静态成员。
    */
    static bool compara(int a,int b)
    {
        string s1 = to_string(a) + to_string(b);
        string s2 = to_string(b) + to_string(a);
        return s1 < s2;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值