31. 整数中1出现的次数(从1到n整数中1出现的次数)
- 求出1-13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1-13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。
// Soluntion:(1)计算1-n每个数字,余10后1的个数总和——效率O(n*logn);
// (2)计算每一位上出现1的次数——效率O(logn).
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
if (n < 0) {
return 0;
}
int count = 0;
int pos = 1; //个位,循环*10,逐位相加
while (n/pos != 0) {
int high = n/(pos*10); //高位
int cur = (n/pos)%10; //当前位
int low = n%pos; //低位
if (cur == 0) {
count += high*pos;
} else if (cur == 1) {
count += high*pos + low+1;
} else {
count += (high+1)*pos;
}
pos *= 10;
}
return count;
}
};
Solution(2):
设N = abcde ,其中abcde分别为十进制中各位上的数字。
如果要计算百位上1出现的次数,它要受到3方面的影响:百位上的数字,百位以下(低位)的数字,百位以上(高位)的数字。
① 如果百位上数字为0,百位上可能出现1的次数由更高位决定。比如:12013,则可以知道百位出现1的情况可能是:100-199,1100-1199,2100-2199,,...,11100-11199,一共1200个。可以看出是由更高位数字(12)决定,并且等于更高位数字(12)乘以当前位数(100)。
② 如果百位上数字为1,百位上可能出现1的次数不仅受更高位影响还受低位影响。比如:12113,则可以知道百位受高位影响出现的情况是:100-199,1100-1199,2100-2199,,....,11100-11199,一共1200个,等于更高位数字(12)乘以 当前位数(100)。但同时它还受低位影响,百位出现1的情况是:12100-12113,一共114个,等于低位数字(113)+1。
③ 如果百位上数字大于1(2~9),则百位上出现1的情况仅由更高位决定,比如12213,则百位出现1的情况是:100-199,1100-1199,2100-2199,...,11100-11199,12100-12199,一共有1300个,并且等于更高位数字+1(12+1)乘以当前位数(100)。
32. 把数组排成最小的数【O(nlogn)】
- 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
// Solution:(1)数字全排列拼接(类似于“字符串的排列”题),求最大值;
// (2)拼接n和m,如果nm numbers) {
int len = numbers.size();
if (len == 0)
return "";
sort(numbers.begin(), numbers.end(), cmp);
string res;
for (int i = 0; i < len; i ++) {
res += to_string(numbers[i]);
}
return res;
}
static bool cmp (int a, int b) {
string str1 = to_string(a) + to_string(b);
string str2 = to_string(b) + to_string(a);
return str1 < str2;
}
};
33. 丑数【空间换时间】
- 把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
// Solution:
// (1)逐个数字循环除以2,3,5,最后得到1,则为丑数,时间效率极差;
// (2)用数组从小到大保存丑数,逐个计算。
class Solution {
public:
int GetUglyNumber_Solution(int index) {
if (index <= 0) {
return 0;
}
vector uglyNumbers(index);
uglyNumbers[0] = 1;
int uglyIndex = 1; // 从第二个数开始
int p2 = 0, p3 = 0, p5 = 0;
while (uglyIndex < index) {
uglyNumbers[uglyIndex] = min(uglyNumbers[p2]*2,
min(uglyNumbers[p3]*3,uglyNumbers[p5]*5));
while (uglyNumbers[p2]*2 <= uglyNumbers[uglyIndex])
p2 ++;
while (uglyNumbers[p3]*3 <= uglyNumbers[uglyIndex])
p3 ++;
while (uglyNumbers[p5]*5 <= uglyNumbers[uglyIndex])
p5 ++;
uglyIndex ++;
}
return uglyNumbers[index-1];
}
};
34. 第一个只出现一次的字符【哈希表,空间换时间】
- 在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置
// Solution:(1)逐个统计每个字符出现的次数——时间效率O(n);
// (2)使用哈希表的方法存每个字符出现的次数,扫描两遍原字符——时间O(n).
class Solution {
public:
int FirstNotRepeatingChar(string str) {
if (str.size() == 0)
return -1;
int countChar[256] = {0}; //ASCII码8位,可表示256个字符
for (int i = 0; i < str.size(); i ++) {
countChar[str[i]] ++;
}
for (int i = 0; i < str.size(); i ++) {
if (countChar[str[i]] == 1)
return i;
}
return -1;
}
};
35. 数组中的逆序对【需要注意递归调用参数位置,并且需要使用long】
- 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
示例1:
输入:1,2,3,4,5,6,7,0
输出:7
// Solution:(1)顺序扫描,逐个比较后续数字——时间复杂度O(n^2);
// (2)归并排序,过程中计算逆序对的数量——时间O(n*logn),空间O(n).
class Solution {
public:
int InversePairs(vector data) {
if (data.size() == 0)
return 0;
vector copy(data); // 复制data数组
return InversePairsCore(data, copy, 0, data.size()-1);
}
long InversePairsCore(vector& data, vector& copy, long start, long end){
if (start == end) {
copy[start] = data[start];
return 0;
}
long len = (end - start)/2;
long left_count = InversePairsCore(copy, data, start, start+len); // 传地址,返回第二个参数是经过排序的数组
long right_count = InversePairsCore(copy, data, start+len+1, end);// copy在前,是因为后续需要data数组是经过排序的
// 数组左侧、右侧最后一个数字下标
long left_index = start + len;
long right_index = end;
long copy_index = end;
long count = 0;
while (left_index >= start && right_index >= start+len+1) {
if (data[left_index] > data[right_index]) {
count += (right_index - (start+len));
copy[copy_index --] = data[left_index --];
} else {
copy[copy_index --] = data[right_index --];
}
}
while (left_index >= start) {
copy[copy_index --] = data[left_index --];
}
while (right_index >= start + len + 1) {
copy[copy_index --] = data[right_index -- ];
}
return (left_count% 1000000007 + right_count% 1000000007 + count% 1000000007) % 1000000007;
}
};