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