第三十一题:求1~n中所有整数里面1出现次数和
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数
class Solution {
/*
本题解法我们可以用两个数字来模拟即可懂
43147
43247
对于百位来说,是不同的,在下列程序运行的结果也不一样
因为我们找规律可以发现,百位出现1的次数,由前后两部分影响
并且如果它还是1的话,后面一部分影响的值有变换
+8的意思是:如果当前位大于1使得其进一位,方便计算
*/
public:
int NumberOf1Between1AndN_Solution(int n)
{
int a,b,cnt=0;
for(int m=1;m<=n;m*=10){
a=n/m;
b=n%m;
cnt+=(a+8)/10*m+(a%10==1?1:0)*(b+1);
}
return cnt;
}
};
第三十二题:把数组排成最小的数
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323
/*
sort中的比较函数compare要声明为静态成员函数或全局函数
因为:非静态成员函数是依赖于具体对象的,而std::sort这类函数是全局的
静态成员函数或者全局函数是不依赖于具体对象的, 可以独立访问,无须创建任何对象实例就可以访问。
同时静态成员函数不可以调用类的非静态成员
*/
class Solution {
private:
static bool cmp(int a,int b)
{
string A=to_string(a)+to_string(b);
string B=to_string(b)+to_string(a);
return A<B;
}
public:
string PrintMinNumber(vector<int> numbers) {
string ans="";
sort(numbers.begin(),numbers.end(),cmp);
for(int i=0;i<numbers.size();i++)
ans+=to_string(numbers[i]);
return ans;
}
};
第三十三题:丑数
把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数
题解:
设定三个指针,分别从同一个位置开始,当指针指向的下一个数字是最小的时候,对应的指针指向移动一个
class Solution {
public:
int GetUglyNumber_Solution(int index) {
if(index==0) return 0;
vector<int>ans(index);
int t2=0,t3=0,t5=0;
ans[0]=1;
for(int i=1;i<index;i++){
ans[i]=min(2*ans[t2],min(3*ans[t3],5*ans[t5]));
if(ans[i]==ans[t2]*2) t2++;
if(ans[i]==ans[t3]*3) t3++;
if(ans[i]==ans[t5]*5) t5++;
}
return ans[index-1];
}
};
第三十四题:第一个只出现一次的字符
在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置
题解:
hash,map(红黑树)等等
class Solution {
public:
int FirstNotRepeatingChar(string str) {
map<char,int>mp;
for(int i=0;i<str.size();i++)
mp[str[i]]++;
for(int i=0;i<str.size();i++)
if(mp[str[i]]==1) return i;
return -1;
}
};
第三十五题:数组的逆序数对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
数据范围有点大,不能暴力
搞过acm的都知道可以用,线段树,树状数组,归并思想
下面代码使用归并思想:
递归到叶子节点后再返回上一级合并,这里使用一个辅助数组,但是利用了辅助数组却没有把辅助数组的内容复制回去到原数组,见代码注释即可理解
递归到叶子节点很简单,合并的时候见下图
class Solution {
private:
long long deal(vector<int> &data,vector<int> &cp,int start,int end)
{
if(start==end){
cp[start]=data[start];
return 0;
}
int len=(end-start)/2;
long long left=deal(cp,data,start,start+len);//这里直接交换了数组,就不需要再把辅助数组复制回去
long long right=deal(cp,data,start+len+1,end);
int i=start+len,j=end;
int index=end;
long long cnt=0;
while(i>=start&&j>=start+len+1){
if(data[i]>data[j]){
cp[index--]=data[i--];
cnt+=j-start-len;
}
else cp[index--]=data[j--];
}
while(i>=start) cp[index--]=data[i--];
while(j>=start+len+1) cp[index--]=data[j--];
return (left+right+cnt)%1000000007;
}
public:
int InversePairs(vector<int> data) {
int size=data.size();
if(size<=0) return 0;
vector<int> cp=data; //这里已经保证了两个数组一致
long long cnt=deal(data,cp,0,size-1);
return cnt%1000000007;
}
};
第三十六题:两个链表的第一个公共节点
输入两个链表,找出它们的第一个公共结点
题解:根据结构体可以发现,一旦有公共节点,那么两个链表的尾部就一定是相同的
所以,我们先跑一边得到链表的长度,然后再把最长的先跑相应节点使得两条链表尾部长度一样,最后再一起跑,如果相同肯定会一起到达尾部,在此过程中就可以碰到第一个相同的节点返回即可
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
int a=0,b=0,t;
ListNode *p1=pHead1,*p2=pHead2;
while(p1) p1=p1->next,a++;
while(p2) p2=p2->next,b++;
if(a>b){
t=a-b;
while(t--) pHead1=pHead1->next;
t=b;
}
else if(b>a){
t=b-a;
while(t--) pHead2=pHead2->next;
t=a;
}
else t=a;
while(t&&(pHead1->val)!=(pHead2->val)){
pHead1=pHead1->next;
pHead2=pHead2->next;
t--;
}
return pHead1;
}
};