29. 连续子数组的最大和
要求
- 时间限制:1秒
- 空间限制:32768K
- 热度指数:202058
- 本题知识点: 数组
题目描述
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
思路
思路一:暴力求解
该方法为暴力计算,时间复杂度为 O ( n 3 ) O(n^3) O(n3),空间复杂度为 O ( 1 ) O(1) O(1)。
C++实现
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
int length = array.size();
if (length==0) return 0;
if (length==1) return array[0];
int maxSum = array[0];
int temp = 0;
for (int i=0; i<length; i++){ // 控制从哪一个元素开始
for (int j=1; j<=length&&i+j<=length; j++){ // 控制连续子序列长度
for (int k=i; k<i+j; k++){
temp += array[k];
}
maxSum = temp>maxSum?temp:maxSum;
temp = 0;
}
}
return maxSum;
}
};
- 运行时间:4ms
- 占用内存:488k
思路二:动态规划
使用动态规划的思想时间复杂度仅为
O
(
n
)
O(n)
O(n),空间复杂度为
O
(
1
)
O(1)
O(1).
假设
F
(
i
)
F(i)
F(i)为以
a
r
r
a
y
[
i
]
array[i]
array[i]结尾的序列的最大和,
r
e
s
(
i
)
res(i)
res(i)为
i
i
i之前所有情况中的最大和。则有
F
(
i
)
=
m
a
x
(
F
(
i
−
1
)
+
a
r
r
a
y
[
i
]
,
a
r
r
a
y
[
i
]
)
F(i) = max(F(i-1)+array[i], array[i])
F(i)=max(F(i−1)+array[i],array[i])
通俗点说其实就是如果
F
(
i
−
1
)
>
0
F(i-1)>0
F(i−1)>0则会对整个序列和起正面效果,我们将其保留并加上当前元素;否则,保留它对整个子序列之和是有害而无益,因此我们将其重置为当前元素。
r
e
s
(
i
)
=
m
a
x
(
r
e
s
(
i
−
1
)
,
F
(
i
)
)
res(i)=max(res(i-1), F(i))
res(i)=max(res(i−1),F(i))
此式是为了保证
r
e
s
(
i
)
res(i)
res(i)一定为
a
r
r
a
y
[
i
]
array[i]
array[i]元素之前的所有可能子序列中和最大的。
注意:
F
F
F和
r
e
s
res
res的初始值设定为
a
r
r
a
y
[
0
]
array[0]
array[0]而不是
0
0
0可以避免
a
r
r
a
y
array
array元素全为负数出现错误。
C++实现
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
int length = array.size();
if (length==0) return 0;
int maxSum = array[0];
int curSum = array[0];
for (int i=1; i<length; i++){
if (curSum+array[i] > array[i])
curSum += array[i];
else
curSum = array[i];
if (curSum > maxSum)
maxSum = curSum;
}
return maxSum;
}
};
python实现
# -*- coding:utf-8 -*-
class Solution:
def FindGreatestSumOfSubArray(self, array):
# write code here
if len(array) == 0:
return
curSum = array[0]
maxSum = array[0]
for i in range(1, len(array)):
# curSum > 0
if curSum + array[i] > array[i]:
curSum += array[i]
# curSum <= 0
else:
curSum = array[i]
maxSum = curSum if curSum>maxSum else maxSum
return maxSum
30. 整数中1出现的次数
题目描述
求出 1 − 13 1-13 1−13的整数中1出现的次数,并算出 100 − 1300 100-1300 100−1300的整数中 1 1 1出现的次数?为此他特别数了一下 1 13 1~13 1 13中包含 1 1 1的数字有 1 、 10 、 11 、 12 、 13 1、10、11、12、13 1、10、11、12、13因此共出现 6 6 6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从 1 1 1 到 n n n 中 1 1 1出现的次数)。
思路:归纳统计
统计每位上面可能出现1的次数:
- 个位(i=1)
0-9的范围内只出现了1个1.考虑132这个数,可以确定1-130出现了13个1,对于余下的数(2)我们需要判断其和1的大小,这里有2>1,因此还需要加上这个1.
( n / 10 ) ∗ 1 + i f ( n % 10 > 1 ) 1 e l i f ( n % 10 < 1 ) 0 e l s e n % 10 − i + 1 (n/10)*1+\ if\ (n\%10>1)\ 1\ elif\ (n\%10<1)\ 0\ else\ n\%10-i+1 (n/10)∗1+ if (n%10>1) 1 elif (n%10<1) 0 else n%10−i+1 - 十位(i=10)
- 百位(i=100)
. . . ... ...
这里面有个判断条件很重要,即终止条件 i < = n i<=n i<=n.
C++实现
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
if (n<=0)
return 0;
int sum = 0;
for (int i=1; i<=n; i*=10){
long driver = i * 10;
sum += (n / driver) * i;
if (n%driver > 2*i-1)
sum += i;
else if (n%driver < i)
continue;
else
sum += n%driver - i + 1;
}
return sum;
}
};
python实现
# -*- coding:utf-8 -*-
class Solution:
def NumberOf1Between1AndN_Solution(self, n):
# write code here
if n <= 0:
return 0
count = 0
i = 1
while i <= n:
driver = i * 10
count += (n // driver) * i
print(i, count)
if n%driver > 2*i-1:
count += i
elif i <= n%driver <= 2*i-1:
count += n%driver-i+1
i = i * 10
return count
31. 把数组排成最小的数
题目描述
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
本题知识点:数组
思路
考虑对数组中的元素转为字符串形式,再对其进行排序,排序规则为若 i n t ( s t r ( x ) + s t r ( y ) ) > i n t ( s t r ( y ) + s t r ( x ) ) int(str(x)+str(y))>int(str(y)+str(x)) int(str(x)+str(y))>int(str(y)+str(x)),则 x > y x>y x>y,反之 y < = x y<=x y<=x.
python实现
# -*- coding:utf-8 -*-
class Solution:
def PrintMinNumber(self, numbers):
# write code here
if not numbers:
return ''
lmd = lambda x, y: int(str(x)+str(y))-int(str(y)+str(x))
numbers = sorted(numbers, cmp=lmd)
return ''.join([str(s) for s in numbers])
Tips:
- cmp函数当返回正值时,表示的是前者大于后者,这时的排序是从小到大的。
- cmp函数当返回正值时,表示的是后者大于前者,这时的排序是从大到小的。
import functools
a = [1, 3, 2, 4]
# lmd1 = lambda x, y: x - y
def lmd1(x, y):
if x > y:
return 1
elif x < y:
return -1
else:
return 0
def lmd2(x, y):
if x > y:
return -1
elif x < y:
return 1
else:
return 0
a = sorted(a, key=functools.cmp_to_key(lmd1))
print(a)
# lmd2 = lambda x, y: y - x
a = sorted(a, key=functools.cmp_to_key(lmd2))
print(a)
# result:
# [1, 2, 3, 4]
# [4, 3, 2, 1]