题目1524:复杂链表的复制
思路:在每个链表结点后面复制此结点,将复制后的链表分离成两个链表即可,代码如下:
#include <cstdio>
//#include <iostream.h>
using namespace std;
struct Node {
int val;
Node *next;
Node *other;
void setValue(int val){
this->val = val;
next=NULL;
other=NULL;
}
};
void copyList(Node *head){
Node *pHead = head;
Node *nodeToCopy=head;
//复制
while (pHead!=NULL) {
nodeToCopy=new Node();
nodeToCopy->setValue(pHead->val);
nodeToCopy->next=pHead->next;
nodeToCopy->other=pHead->other;
pHead->next=nodeToCopy;
pHead=nodeToCopy->next;
}
//修正任意指针
while (pHead!=NULL) {
pHead->next->other=pHead->other->next;
pHead=pHead->next->next;
}
}
Node * spliteList(Node *head){
Node *pCopy = head;
Node *pHead = head->next;
Node *node= head;
while (node!=NULL) {
pCopy=node->next;
node->next=pCopy->next;
node=node->next;
}
return pHead;
}
int main()
{
int n,val;
Node linkList[1000];
while (scanf("%d",&n)!=EOF) {
scanf("%d",&val);
Node *head = new Node();
head->setValue(val);
Node *node=head;
linkList[0]=*head;
for (int i=1; i<n; i++) {
scanf("%d",&val);
Node *tmpNode = new Node();
tmpNode->setValue(val);
node->next=tmpNode;
node=tmpNode;
linkList[i]=*tmpNode;
}
node=head;
while(node!=NULL) {
scanf("%d",&val);
if (val!=0) {
node->other=&linkList[val-1];
}
node=node->next;
}
copyList(head);
node = spliteList(head);
if (node!=NULL) {
printf("%d",node->val);
if (node->other!=NULL) {
printf(" %d\n",node->other->val);
}else{
printf(" 0\n");
}
node=node->next;
}
while (node!=NULL) {
printf("%d",node->val);
if (node->other!=NULL) {
printf(" %d\n",node->other->val);
}else{
printf(" 0\n");
}
node=node->next;
}
}
return 0;
}
题目1503:二叉搜索树与双向链表
思路:中序遍历,将左孩子指向前一个结点,右孩子指向下一个结点,代码如下:
#include <cstdio>
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
void setValue(int val){
this->m_nValue=val;
m_pLeft=m_pRight=NULL;
}
};
BinaryTreeNode * constructTree(BinaryTreeNode *root){
int val;
scanf("%d",&val);
if (val!=0)
{
root=new BinaryTreeNode();
root->setValue(val);//同时把左右子树变为空了
root->m_pLeft=constructTree(root->m_pLeft);
root->m_pRight=constructTree(root->m_pRight);
}
return root;
}
void ConvertNode(BinaryTreeNode* pNode, BinaryTreeNode** pLastNodeInList)
{
if(pNode == NULL)
return;
BinaryTreeNode *pCurrent = pNode;
if (pCurrent->m_pLeft != NULL)
ConvertNode(pCurrent->m_pLeft, pLastNodeInList);
pCurrent->m_pLeft = *pLastNodeInList;
if(*pLastNodeInList != NULL)
(*pLastNodeInList)->m_pRight = pCurrent;
*pLastNodeInList = pCurrent;
if (pCurrent->m_pRight != NULL)
ConvertNode(pCurrent->m_pRight, pLastNodeInList);
}
BinaryTreeNode* Convert(BinaryTreeNode* pRootOfTree)
{
BinaryTreeNode *pLastNodeInList = NULL;
ConvertNode(pRootOfTree, &pLastNodeInList);
// pLastNodeInList指向双向链表的尾结点,
// 我们需要返回头结点
BinaryTreeNode *pHeadOfList = pLastNodeInList;
while(pHeadOfList != NULL && pHeadOfList->m_pLeft != NULL)
pHeadOfList = pHeadOfList->m_pLeft;
return pHeadOfList;
}
void PrintList(BinaryTreeNode* pRoot)
{
if(pRoot == NULL)
return;
BinaryTreeNode* pHead = pRoot;
while(pHead != NULL)
{
printf("%d ",pHead->m_nValue);
pHead = pHead->m_pRight;
}
}
int main()
{
int n;
while (scanf("%d",&n)!=EOF) {
for (int i=0;i<n;i++)
{
BinaryTreeNode *root =NULL;
root = constructTree(root);
root = Convert(root);
PrintList(root);
printf("\n");
}
}
return 0;
}
题目1369:字符串的排列
最简单的是调用系统函数:next_permutation,或者自己实现此函数,自己实现函数代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
//如果还有下一个排列,返回1,否则返回0
int next_permutation(char *arr, int len)
{
int i, j, k, l;
// Step 1, find the largest k s.t. arr[k] < arr[k+1]
for (k = len - 2; k >= 0; k--)
if (arr[k] < arr[k + 1])
break;
if (k < 0)
return 0;
// Step 2, find the largest l(el) s.t. arr[k] < arr[l]
for (l = len - 1; l > k; l--)
if (arr[k] < arr[l])
break;
// Step 3, swap arr[k] & arr[l]
swap(arr[k] , arr[l]);
// Step 4, reverse arr[k+1, ]
reverse(arr+k+1,arr+len);
return 1;
}
int main(){
char str[10];
while(gets(str)){
int len=strlen(str);
sort(str,str+len);
puts(str);
while(next_permutation(str,len)){
puts(str);
}
}
return 0;
}
题目1370:数组中出现次数超过一半的数字
有多种方法,比如先排序(全排序,或用快排只定位出中间数),找中间的数,因为超过一半的数肯定在中间。剑指offer里提供了另一种巧妙的方法:遍历数组,遇到相同的数则加1,否则减1,如果小于0,则以新数为起点,并标记为1.最后剩下的数必然是可能超过一半的数。代码如下:
#include<stdio.h>
#include<algorithm>
using namespace std;
bool CheckMoreThanHalf(int* numbers, int length, int number)
{
int times = 0;
for(int i = 0; i < length; ++i)
{
if(numbers[i] == number)
times++;
}
return times > length>>1;
}
int getMoreThanHalfNumber(int data[],int n)
{
if(data == NULL || n <= 0)
return -1;
int result = data[0];
int times = 1;
for(int i = 1; i < n; ++i)
{
if(times == 0)
{
result = data[i];
times = 1;
}
else if(data[i] == result)
times++;
else
times--;
}
return CheckMoreThanHalf(data, n, result)?result:-1;
}
int main()
{
int data[100005];
int n;
while(scanf("%d",&n)!=EOF){
for (int i=0;i<n;i++)
{
scanf("%d",&data[i]);
}
printf("%d\n",getMoreThanHalfNumber(data,n));
}
return 0;
}
题目1371:最小的K个数
跟上题一样,可以用普通排序或快排的灵活应用解决,代码如下:
普通排序:
#include<stdio.h>
#include<algorithm>
#define N 200001
using namespace std;
void getMinKNumber(int data[],int n,int k)
{
if (k>n)
{
return ;
}
sort(data,data+n);
for(int i=0;i<k-1;i++)
{
printf("%d ",data[i]);
}
printf("%d\n",data[k-1]);
}
int main()
{
int n,k;
int data[N];
while(scanf("%d%d",&n,&k)!=EOF)
{
for(int i=0;i<n;i++)
{
scanf("%d",&data[i]);
}
getMinKNumber(data,n,k);
}
}
快排灵活应用:
#include<stdio.h>
#include<algorithm>
#define N 200001
using namespace std;
int Partition(int data[], int length, int start, int end)
{
if(data == NULL || length <= 0 || start < 0 || end >= length)
return -1;
int index = start;
swap(data[index], data[end]);
int small = start - 1;
for(index = start; index < end; ++ index)
{
if(data[index] < data[end])
{
++ small;
//如果当前遍历值比取的值小且当前值不是small指向的值,把小的值往前置换
if(small != index)
swap(data[index], data[small]);
}
}
++ small;
swap(data[small], data[end]);
return small;
}
//利用快排找出前k个数,再排序
void getMinKNumber(int data[],int n,int k)
{
if(data == NULL || k > n || n <= 0 || k <= 0)
return;
int start = 0;
int end = n - 1;
int index = Partition(data, n, start, end);
while(index != k - 1&&index!=-1)
{
if(index > k - 1)
{
end = index - 1;
index = Partition(data, n, start, end);
}
else
{
start = index + 1;
index = Partition(data, n, start, end);
}
}
sort(data,data+k);
for(int i=0;i<k-1;i++)
{
printf("%d ",data[i]);
}
printf("%d\n",data[k-1]);
}
int main()
{
int n,k;
int data[N];
while(scanf("%d%d",&n,&k)!=EOF)
{
for(int i=0;i<n;i++)
{
scanf("%d",&data[i]);
}
getMinKNumber(data,n,k);
}
}
题目1372:最大子向量和(连续子数组的最大和)
记录当前和以及最大和,如果当前和大于最大和,则更新最大和,如果当前和小于0,则重新计当前和,代码如下:
#include <cstdio>
//#include <iostream.h>
using namespace std;
int main()
{
int n,maxSum,maxStartIndex,currentStartIndex,eIndex,currentSum;
int data;
while (scanf("%d",&n)&&n!=0) {
maxSum = -1001;
currentSum = 0;
maxStartIndex = 0;
eIndex=0;
currentStartIndex = 0;
for (int i=0; i<n; i++) {
scanf("%d",&data);
currentSum+=data;
//如果当前和大于最大和,则更新最大和,并更新位置
if (currentSum>maxSum) {
eIndex=i;
maxStartIndex=currentStartIndex;
maxSum = currentSum;
}
//如果当前和小于0,则重新开始计和,并更新起始位置
if(currentSum<0){
currentSum = 0;
currentStartIndex = i+1;
}
}
printf("%d %d %d\n",maxSum,maxStartIndex,eIndex);
}
return 0;
}
题目1373:整数中1出现的次数(从1到n整数中1出现的次数)
将数据分段来求,利用数学规律,代码如下:
普通方法:
#include <cstdio>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
int NumberOf1(const char* strN)
{
if(!strN || *strN < '0' || *strN > '9' || *strN == '\0')
return 0;
int first = *strN - '0';
unsigned int length = static_cast<unsigned int>(strlen(strN));
if(length == 1 && first == 0)
return 0;
if(length == 1 && first > 0)
return 1;
// 假设strN是"21345"
// numFirstDigit是数字10000-19999的第一个位中1的数目
int numFirstDigit = 0;
if(first > 1)
numFirstDigit = pow(10,length - 1);
else if(first == 1)
numFirstDigit = atoi(strN + 1) + 1;
// numOtherDigits是01346-21345除了第一位之外的数位中1的数目
int numOtherDigits = first * (length - 1) * pow(10,length - 2);
// numRecursive是1-1345中1的数目
int numRecursive = NumberOf1(strN + 1);
return numFirstDigit + numOtherDigits + numRecursive;
}
int main()
{
int a,b;
char c1[15],c2[15];
while (scanf("%d%d",&a,&b)!=EOF) {
if (a>b)
{
swap(a,b);
}
int n=0;
if (a>0) {
sprintf(c1, "%d",a-1);
n=NumberOf1(c1);
}
int m=0;
if (b>0) {
sprintf(c2, "%d",b);
m=NumberOf1(c2);
}
printf("%d\n",m-n);
}
return 0;
}
高手的代码:
#include <stdio.h>
int f(int z)
{
int i=9,c=0,v=1e9,d;
while(z){
for (;v>z;v/=10,--i);
d=z/v;//当前最高位数字
z%=v;//除去最高位剩下的数字
//最高位大于1,则最高位为1的情况有v种,否则为除去最高位剩下的数字加上1种
//除去最高位为1的情况,将剩下的数字按整(v/10)划分,可划分为d份,第一份中任选一位为1,其他位可以0~9之间任选,根据排列组合
//有d*v/10*i种情况。1的总的个数为两者两加
c+=d*v/10*i+(d>1?v:z+1);
}
return c;
}
int main()
{
int a,b,i;
while(scanf("%d %d",&a,&b)!=EOF)
{
//a>b时用异或的方法调换一下,
//原理,如果a与b中某一位相同,则异或之后为0,如果此位为1(0),则0与了b中的1(0)异或之后依然是1(0)
//如果a与b中某一位不相同,则异或之后为1,如果a的此位为1(0),则1与b中的0(1)异或之后是1(0)
//两种情况均实现了此位上的a与b的调换
a>b?(a^=b,b^=a,a^=b):0;
printf("%d\n",f(b)-(a?f(a-1):0));
}
}
题目1504:把数组排成最小的数
关键在于定义比较函数,比较的是两个数拼接后的字符串大小,而不是两个数的大小,代码如下:
#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<algorithm>
#define MAXN 101
using namespace std;
string str[MAXN];
int cmp(string a,string b)
{
string str1=a+b;
string str2=b+a;
if(str1<str2) return 1;
else return 0;
}
int main()
{
int n;
int i,j;
while(scanf("%d",&n)!=EOF)
{
if(n==0) continue;
for(i=0;i<n;i++) cin>>str[i];
sort(str,str+n,cmp);
for(i=0;i<n;i++) cout<<str[i];
cout<<endl;
}
return 0;
}
通过前面的丑数产生后面的丑数,代码如下:
#include <cstdio>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
int getMin(int i,int j,int k){
return i<j?(i<k?i:k):(j<k?j:k);
}
int numbers[1500];
int getUglyNumber(int n){
numbers[0]=1;
int *number2 = numbers;
int *number3 = numbers;
int *number5 = numbers;
int index=1;
while (index<n) {
numbers[index]=getMin(*number2*2, *number3*3, *number5*5);
while (*number2*2<=numbers[index]) {
number2++;
}
while (*number3*3<=numbers[index]) {
number3++;
}
while (*number5*5<=numbers[index]) {
number5++;
}
index++;
}
return numbers[index-1];
}
int main()
{
int n;
while (scanf("%d",&n)!=EOF) {
printf("%d\n",getUglyNumber(n));
}
return 0;
}
题目1283:第一个只出现一次的字符
遍历两次,第一次统计每个字符出现的次数(用一个长度为256的数组存储),第二次找到只出现一次的字符,代码如下:
#include <cstdio>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
#define MAPLENGTH 256
char getFirstChar(char *str){
int map[MAPLENGTH];
unsigned long len=strlen(str);
int end='A'+26;
for (int i='A'; i<end; i++) {
map[i]=0;
}
for (int i=0; i<len; i++) {
map[str[i]]++;
}
for (int i=0; i<len; i++) {
if(map[str[i]]==1){
return i;
}
}
return -1;
}
int main()
{
char str[10001];
while (scanf("%s",str)!=EOF) {
printf("%d\n",getFirstChar(str));
}
return 0;
}
题目1348:数组中的逆序对
归并排序的同时统计逆序对,代码如下:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#define LENGTH 100001
using namespace std;
int copys[LENGTH];
long long InversePairs(int nums[],int copys[],int s,int e)
{
if (s==e) {
copys[s]=nums[s];
return 0;
}
int length = (e-s)>>1;
long long left =InversePairs(copys, nums, s, s+length);
long long right=InversePairs(copys, nums, s+length+1, e);
long long count=0;
int rightStart = s+length;
int i=s+length;
int copyIndex=e;
while (i>=s&&e>rightStart) {
if (nums[i]>nums[e]) {
copys[copyIndex--]=nums[i--];
count+=e-rightStart;
}else{
copys[copyIndex--]=nums[e--];
}
}
for (; i>=s; i--) {
copys[copyIndex--]=nums[i];
}
for (; e>rightStart; e--) {
copys[copyIndex--]=nums[e];
}
return left+right+count;
}
long long InversePairs(int nums[],int length)
{
if (nums==NULL||length<=0) {
return 0;
}
for (int i=0; i<length; i++) {
copys[i]=nums[i];
}
return InversePairs(nums,copys,0,length-1);
}
int main()
{
int n;
int nums[LENGTH];
while(scanf("%d",&n)!=EOF)
{
for (int i=0; i<n; i++) {
scanf("%d",&nums[i]);
}
printf("%lld\n",InversePairs(nums,n));
}
return 0;
}
题目1505:两个链表的第一个公共结点
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#define LENGTH 1001
using namespace std;
/*
*这道题推荐的解法是首先遍历链表长度,长的链表先走两个长度之差步,然后同时往前走,第一个相同的点就是第一个公共结点
*由于题目给的输入不好构建这两个链表,故用了偷懒的方法了。
*/
void GetLastSame(int nums1[],int nums2[],int m,int n)
{
int i=0;
int *shortNum = nums1;
int *longNum = nums2;
int k,min;
if (m>n) {
shortNum=nums2;
longNum=nums1;
k =m-n;
min = n;
}else{
k =n - m;
min = m;
}
while (longNum[k+i]!=shortNum[i]&&i<min) {
i++;
}
if (i>=min) {
printf("My God\n");
}else{
printf("%d\n",shortNum[i]);
}
}
int main()
{
int m,n;
int nums1[LENGTH];
int nums2[LENGTH];
while(scanf("%d%d",&m,&n)!=EOF)
{
for (int i=0; i<m; i++) {
scanf("%d",&nums1[i]);
}
for (int i=0; i<n; i++) {
scanf("%d",&nums2[i]);
}
GetLastSame(nums1,nums2,m,n);
}
return 0;
}
题目1349:数字在排序数组中出现的次数
用二分法找到该数第一次出现和最后一次出现的位置,相减得出,代码如下:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#define LENGTH 1000001
using namespace std;
int GetFirstK(int *nums,int length,int k,int s,int e)
{
if (s>e) {
return -1;
}
int mid = (s+e)>>1;
int midData =nums[mid];
if (midData==k) {
if (mid==0||nums[mid-1]!=k) {
return mid;
}else{
e=mid - 1;
}
}else if(k<midData){
e=mid-1;
}else{
s=mid + 1;
}
return GetFirstK(nums, length, k,s, e);
}
int GetLastK(int *nums,int length,int k,int s,int e)
{
if (s>e) {
return -1;
}
int mid = (s+e)>>1;
int midData =nums[mid];
if (midData==k) {
if (mid==length-1||nums[mid+1]!=k) {
return mid;
}else{
s=mid + 1;
}
}else if(k<midData){
e=mid-1;
}else{
s=mid + 1;
}
return GetLastK(nums, length, k,s, e);
}
int getKCounts(int *nums,int length,int k){
int count = 0;
if (nums!=NULL&&length>0) {
int first = GetFirstK(nums,length,k, 0, length-1);
int last = GetLastK(nums,length,k, 0, length-1);
if (first!=-1&&last!=-1) {
count = last - first +1;
}
}
return count;
}
int main()
{
int m,n,k;
int nums[LENGTH];
while(scanf("%d",&m)!=EOF)
{
for (int i=0; i<m; i++) {
scanf("%d",&nums[i]);
}
scanf("%d",&n);
for (int i=0; i<n; i++) {
scanf("%d",&k);
printf("%d\n",getKCounts(nums, m,k));
}
}
return 0;
}
题目1350:二叉树的深度
先求左右子树的深度,递归求解,代码如下:
#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<algorithm>
#define MAXN 11
using namespace std;
typedef struct {
//int val;
int left;
int right;
} BinaryTreeNode;
int getTreeDepth(BinaryTreeNode *notes,int idx){
if (idx==-2) return 0;
int left = notes[idx].left==-2?0:getTreeDepth(notes,notes[idx].left);
int right = notes[idx].right==-2?0:getTreeDepth(notes,notes[idx].right);
return left>right?left+1:right+1;
}
int main()
{
int n;
BinaryTreeNode notes[MAXN];
while(cin >>n)
{
if(n==0) continue;
for(int i=0;i<n;i++)
{
cin >> notes[i].left >> notes[i].right;
--notes[i].left;
--notes[i].right;
}
int depth = getTreeDepth(notes,0);
cout<<depth<<endl;
}
return 0;
}
题目1351:数组中只出现一次的数字
先按位异或,再通过异或结果对数组分组(根据某位是否为1),再分别异或,代码如下:
#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<algorithm>
#define MAXN 1000000
using namespace std;
int nums[MAXN];
int getNumber(int *num,int *num1,int *num2 , int n){
int resultExclusiveOR = 0;
int mask = 1;
for (int i = 0; i < n; i++)
resultExclusiveOR^=num[i];
*num1=0;
*num2=0;
while( !(mask & resultExclusiveOR) ) mask <<= 1;
for (int i = 0; i < n; i++)
{
if (num[i]& mask)
*num1^=num[i];
else
*num2^=num[i];
}
if(*num1>*num2)
{
//交换
*num1^=*num2;
*num2^=*num1;
*num1^=*num2;
}
return 0;
}
template <class T>
inline void scan_d(T &ret) {
char c; ret=0;
while((c=getchar())<'0'||c>'9');
while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
}
int main()
{
int n;
while(cin >>n)
{
for(int i=0;i<n;i++)
{
scan_d(nums[i]);
}
if(n<2) continue;
int num1,num2;
getNumber(nums,&num1,&num2,n);
cout<<num1<<" "<<num2<<endl;
}
return 0;
}
mask也可用(resultExclusiveOR & (-resultExclusiveOR))求得,scan_d可以大提高输入速度。
题目1352:和为S的两个数字
分别定义两个指针从前往后或从后往前移动,大小S则移动后面的指针,小于则移动前面的指针,代码如下:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#define LENGTH 1000001
using namespace std;
int nums[LENGTH];
void findSum(int &num1,int &num2,int n,int k){
num1=num2=-1;
int s=0,e=n-1;
while ( s<e ) {
if (nums[s]+nums[e]<k) {
s++;
}else if (nums[s]+nums[e]>k) {
e--;
}else{
num1 = nums[s];
num2 = nums[e];
break;
}
}
}
int main()
{
int n,k;
while(scanf("%d%d",&n,&k)!=EOF)
{
for (int i=0; i<n; i++) {
scanf("%d",&nums[i]);
}
int num1,num2;
findSum(num1,num2,n,k);
printf("%d %d\n",num1,num2);
}
return 0;
}
题目1354:和为S的连续正数序列
类似于上面一题,代码如下:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#define LENGTH 1000001
using namespace std;
void printSum(int s,int e){
while (s<e) {
printf("%d ",s++);
}
printf("%d\n",e);
}
void findSum(int n){
int mid = (n>>1)+1;
int s=1,e=2;
int sum = s+e;
bool find = false;
while (s<mid&&s<e) {
if (sum<n) {
e++;
sum+=e;
}else if (sum>n){
sum-=s;
s++;
}else{
find = true;
printSum(s,e);
sum-=s;
s++;
e++;
sum+=e;
}
}
if (!find) {
printf("Pity!\n");
}
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF&&n>-1)
{
findSum(n);
printf("#\n");
}
return 0;
}
题目1361:翻转单词顺序
先全部翻转,再逐个翻转,代码如下:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#define LENGTH 50001
using namespace std;
char strs[LENGTH];
void reverseChar(char *pBegin,char *pEnd){
if (pBegin==NULL||pEnd==NULL) {
return;
}
while (pBegin<pEnd) {
swap(*pBegin, *pEnd);
pBegin++;
pEnd--;
}
}
void reverseChar(char *str){
char *pBegin = str;
char *pEnd = str;
while (*pEnd!='\0') pEnd++;
pEnd--;
reverseChar(pBegin, pEnd);
pEnd=pBegin;
while (*pBegin!='\0') {
if (*pEnd==' '||*pEnd=='\0') {
if (*pBegin!=' ') {
reverseChar(pBegin, pEnd-1);
pBegin = pEnd+1;
pEnd++;
}else{
pBegin = pEnd+1;
pEnd++;
}
}else{
pEnd++;
}
}
printf("%s\n",str);
}
int main()
{
while(gets(strs))
{
reverseChar(strs);
}
return 0;
}
题目1362:左旋转字符串
先翻转前后两段,再全部翻转,代码如下:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define LENGTH 1001
using namespace std;
char strs[LENGTH];
void reverseChar(char *pBegin,char *pEnd){
if (pBegin==NULL||pEnd==NULL) {
return;
}
while (pBegin<pEnd) {
swap(*pBegin, *pEnd);
pBegin++;
pEnd--;
}
}
void reverseChar(char *str,int k){
long length = strlen(str);
k = k%length;
//翻转前半段
reverseChar(str,str+k-1);
//翻转后半段
reverseChar(str+k,str+length-1);
//翻转全部
reverseChar(str,str+length-1);
printf("%s\n",str);
}
int main()
{
int k;
while(scanf("%s%d",strs,&k)!=EOF)
{
reverseChar(strs,k);
}
return 0;
}
题目1360:乐透之猜数游戏
通过f(n)=f(n-6)+f(n-5)..f(1)求得(假设最大点数为6),用两个数组交替存储。注意要先取两位小数后再比较,不然a不了,代码如下:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
int m=0;
int n=0;
int flag =0;
double a[2][8*10+1];//用两行表示数据,每行都是n个骰子相加能得到的和
void count(int n,int m)
{
flag=1;
memset(a,0,sizeof(a));
for(int i=1;i<=m;i++)//第一个骰子
{
a[1][i]=1.0/m;
}
for(int i=2;i<=n;i++)
{
for(int l=0;l<i;l++)
a[1-flag][l]=0;
for(int j=0;j<=m*i;j++)//计算下一行对应位置的值,依次遍历其前一行每个和的概率,再乘以这个骰子得到对应值的概率,最后相加。
//即考虑了所有这个值能够构成的情况
{
a[1-flag][j] = 0;
int k = 1;
while(k<=j && k<=m)
{
a[1-flag][j] += a[flag][j-k]/m;
k++;
}
}
flag = 1- flag;
}
}
void MaxNum(double *data, int len, double &max, int &index)
{
max = data[0];
for (int i = 1; i < len; ++i)
{
if (max < data[i])
{
max = data[i];
index = i;
}
}
data[index] = 0;
}
int main()
{
while(scanf("%d %d", &n, &m) != EOF)
{
if(n==0)
break;
count(n,m);
for (int i = n; i <= n * m; ++i)
{
a[flag][i] = (int) (a[flag][i] * 100 + 0.5) / 100.0;
}
double max=0;
int maxi=0;
for(int i=0;i<3;i++)
{
MaxNum(a[flag],n*m+1,max,maxi);
printf("%d %.2f\n",maxi, max);
}
printf("\n");
}
}
题目1355:扑克牌顺子
先排序,再用0补全空档,代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int a[20];
int main()
{
int n, num;
int i;
while(scanf("%d", &n) && n)
{
for(i=0; i<n; i++)
scanf("%d", &a[i]);
sort(a, a+n); //小到大排序
num = 0;
i = 0;
while(i<n && a[i]==0)
{
num++;
i++;
}
//num为大小王张数
for(i++; i<n; i++)
{
if(a[i] == a[i-1])
break; //出现相同无法形成顺子
else
//用num减去两张牌的差值,即用大小王填补
num -= (a[i]-a[i-1]-1);
}
//cout << num << endl;
if(i<n || num<0)
//i<n 出现相同牌(除大小王外)
//num<0 需要填补的大小王牌数大于实际大小王牌数
printf("Oh My God!\n");
else
printf("So Lucky!\n");
}
return 0;
}
题目1356:孩子们的游戏(圆圈中最后剩下的数)
用循环链表,或使用数学公式,后者代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int main()
{
int n, m;
while(scanf("%d", &n)&&n>0)
{
scanf("%d", &m);
int last=0;
for (int i=2; i<=n; i++) {
last=(last+m)%i;
}
printf("%d\n",last+1);
}
return 0;
}
题目1506:求1+2+3+...+n
使用构造函数+静态变量,或使用虚函数求解,代码如下:
1、
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;
class A;
A* array[2];
class A{
public:
virtual unsigned int sum(unsigned int n){
return 0;
}
};
class B:public A {
public:
virtual unsigned int sum(unsigned int n){
return array[!!n]->sum(n-1)+n;
}
};
int main()
{
int n=10;
A a;
B b;
array[0]=&a;
array[1]=&b;
while (cin>>n) {
int value = array[1]->sum(n);
printf("%d\n",value);
}
return 0;
}
2、
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
using namespace std;
class A{
public:
A(){
++n;
sum+=n;
}
static void reset(){
n=0;
sum=0;
}
static unsigned int getSum(){
return sum;
}
private:
unsigned static int n;
unsigned static int sum;
};
unsigned int A::n=0;
unsigned int A::sum=0;
int main()
{
int n;
while (cin>>n) {
A::reset();
A *a=new A[n];
int value = A::getSum();
printf("%d\n",value);
delete a;
a=NULL;
}
return 0;
}
题目1507:不用加减乘除做加法
用位运算,先按位异或得到a,再按位与得到b,b<<=1,再对ab做相同操作。效果比直接相加高,代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
using namespace std;
int add(int m,int n){
int sum,carry;
do {
sum=m^n;
carry=(m&n)<<1;
m=sum;
n=carry;
} while (n);
return sum;
}
int main()
{
int m,n;
while (cin>>m>>n) {
printf("%d\n",add(m,n));
}
return 0;
}
题目1508:把字符串转换成整数
要考虑各种情况,代码如下:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
enum Statues{k_valid=0,k_invalid=1};
int g_invalid = k_valid;
long long atoiCore(const char *p,bool minus){
long long result = 0;
int flag=minus?-1:1;
while (*p!='\0') {
if (*p<='9'&&*p>='0') {
result=result*10+flag*(*p-'0');
if ((!minus&&result>0x7FFFFFFF)||(minus&&result<(signed int)0x80000000)) {
result = 0;
break;
}
}else{
result = 0;
break;
}
p++;
}
if (*p=='\0') {
g_invalid = k_valid;
}
return result;
}
int atoi(const char *p){
long long result = 0;
g_invalid=k_invalid;
if (p!=NULL||*p!='\0') {
bool minus = false;
if (*p=='+') {
p++;
}else if (*p=='-') {
p++;
minus = true;
}
if (*p!='\0') {
result = atoiCore(p,minus);
}
}
return (int)result;
}
int main()
{
char strs[50];
while(scanf("%s",strs)!=EOF)
{
int n = atoi(strs);
if (!n&&k_invalid==g_invalid)
printf("My God\n");
else
printf("%d\n",n);
}
return 0;
}
题目1509:树中两个结点的最低公共祖先
先找到两个结点的路径,再找公共祖先,代码如下:
#include <cstdio>
#include <vector>
using namespace std;
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
void setValue(int val){
this->m_nValue=val;
m_pLeft=m_pRight=NULL;
}
};
BinaryTreeNode * constructTree(BinaryTreeNode *root){
int val;
scanf("%d",&val);
if (val!=0)
{
root=new BinaryTreeNode();
root->setValue(val);//同时把左右子树变为空了
root->m_pLeft=constructTree(root->m_pLeft);
root->m_pRight=constructTree(root->m_pRight);
}
return root;
}
bool getNodePath(BinaryTreeNode* pRoot,int pNode,vector<BinaryTreeNode*> &path){
bool found = false;
path.push_back(pRoot);
if (pRoot->m_nValue==pNode) {
return true;
}
if (pRoot->m_pLeft!=NULL) {
found=getNodePath(pRoot->m_pLeft,pNode,path);
}
if (!found&&pRoot->m_pRight!=NULL) {
found=getNodePath(pRoot->m_pRight,pNode,path);
}
if (!found) {
path.pop_back();
}
return found;
}
void PrintTree(const vector<BinaryTreeNode*> &path1,const vector<BinaryTreeNode*> &path2)
{
vector<BinaryTreeNode*>::const_iterator it1 = path1.begin();
vector<BinaryTreeNode*>::const_iterator it2 = path2.begin();
BinaryTreeNode* last=NULL;
while (it1!=path1.end()&&it2!=path2.end()) {
if (*it1==*it2) {
last=*it1;
}else{
break;
}
it1++;
it2++;
}
if (last!=NULL) {
printf("%d\n",last->m_nValue);
}else{
printf("My God\n");
}
}
void freeTree(BinaryTreeNode* pRoot){
}
int main()
{
int n,m1,m2;
while (scanf("%d",&n)!=EOF) {
for (int i=0;i<n;i++)
{
BinaryTreeNode *root =NULL;
root = constructTree(root);
scanf("%d%d",&m1,&m2);
if (m1==0||m2==0) {
printf("My God\n");
continue;
}
vector<BinaryTreeNode*> path1,path2;
getNodePath(root,m1,path1);
getNodePath(root,m2,path2);
PrintTree(path1,path2);
freeTree(root);
}
}
return 0;
}