1 lucky number。给定一个长度为m的数组,其中有m-1个数每个出现n次,只有一个数出现次数不为n次,找出该数字
http://ac.jobdu.com/problem.php?pid=1380
(1) 建立一个辅助数组hash[32],初始化为0;
(2) 每次从控制台读入一个数,转化成二进制表示,第j位累加到hash[j]中;
(3) 对hash数组中每个元素模n,若为0,则表示要求的数中对应位为0,反之为1。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 int func(int n,int m) 2 { 3 const int MaxBit = 32; 4 int hash[MaxBit]; 5 memset(hash,0,sizeof(hash)); 6 for (int i=0; i<m; i++) 7 { 8 int x; 9 scanf("%d",&x); 10 for (int j=0; j<MaxBit; j++) 11 { 12 hash[j] += (x & 1); 13 x >>= 1; 14 } 15 } 16 int t[MaxBit]; 17 for (int j=0; j<MaxBit; j++) 18 { 19 hash[j] %= n; 20 if (hash[j] != 0) 21 { 22 t[j] = 1; 23 } 24 else 25 { 26 t[j] = 0; 27 } 28 } 29 int ans = 0; 30 for (int j=MaxBit-1; j>=0; j--) 31 { 32 ans = ans * 2 + t[j]; 33 } 34 return ans; 35 }
2 给定一个长度为N的数组,其中每个元素的取值范围都是1到N。判断数组中是否有重复的数字。(原数组不必保留)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 void swap(int &a,int &b) 2 { 3 int tmp = a; 4 a = b; 5 b = tmp; 6 } 7 8 bool func(int *a, int n) 9 { 10 for (int i=1; i<=n; i++) 11 { 12 while(a[i]!=i) 13 { 14 int j = a[i]; 15 if (a[j]==j) 16 { 17 return true; 18 } 19 swap(a[i],a[j]); 20 } 21 } 22 return false; 23 }
3 写一个函数,求两个整数的之和,要求在函数体内不得使用+、-、×、÷。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 int add(int x,int y) 2 { 3 char * c = (char *)x; 4 return (int)(&c[y]); 5 }
4 给定一个长度为n的数组,每个元素都为正整数,将其拆分成两个子数组,使得这两个子数组的和尽可能相等。
http://ac.jobdu.com/problem.php?pid=1420
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 bool dp[5000001]; 2 3 int func(int *a,int n) 4 { 5 int total = 0; 6 for (int i=0; i<n; i++) 7 { 8 total += a[i]; 9 } 10 int mid = total/2+1; 11 memset(dp,0,sizeof(dp)); 12 dp[0]=true; 13 int ans = 1<<30; 14 for (int i=0; i<n; i++) 15 { 16 for (int j=mid; j>=0;j--) 17 { 18 if (j-a[i]>=0 && dp[j-a[i]]) 19 { 20 dp[j] = true; 21 int diff = abs(total-2*j); 22 if (diff == 0) 23 { 24 return 0; 25 } 26 if (diff < ans) 27 { 28 ans = diff; 29 } 30 } 31 } 32 } 33 return ans; 34 }
5 子数组之和的最大值 2维
http://ac.jobdu.com/problem.php?pid=1139
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 int sum(int *a,int n) 2 { 3 int t = a[0], ans = a[0]; 4 for (int i=1; i<n; i++) 5 { 6 t = max(a[i],a[i]+t); 7 ans = max(t,ans); 8 } 9 return ans; 10 } 11 12 const int MaxNum = 100; 13 int arr[MaxNum+1][MaxNum+1]; 14 15 int func(int m,int n) 16 { 17 int dp[MaxNum+1]; 18 int ans = -(1<<30); 19 for (int i=0; i<m; i++) 20 { 21 memset(dp,0,sizeof(dp)); 22 for (int j=i; j<m; j++) 23 { 24 for (int k=0; k<n; k++) 25 { 26 dp[k] += arr[j][k]; 27 } 28 int t = sum(dp,n); 29 if (t > ans) 30 { 31 ans = t; 32 } 33 } 34 } 35 return ans; 36 }
6 最近零的连续子序列
http://ac.jobdu.com/problem.php?pid=1376
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 const int MaxNum = 100000; 2 int a[MaxNum+1]; 3 4 struct Helper 5 { 6 int index; 7 int val; 8 }; 9 10 Helper temp[MaxNum+1]; 11 12 bool cmp(Helper h1,Helper h2) 13 { 14 return h1.val < h2.val; 15 } 16 17 int main() 18 { 19 int n; 20 while(cin>>n) 21 { 22 for (int i=0; i<n; i++) 23 { 24 cin>>a[i]; 25 } 26 temp[0].val = a[0]; 27 temp[0].index = 0; 28 bool hasFoundMin = false; 29 for (int i=1; i<n; i++) 30 { 31 temp[i].val = temp[i-1].val+a[i]; 32 temp[i].index = i; 33 if (temp[i].val == 0) 34 { 35 hasFoundMin = true; 36 break; 37 } 38 } 39 if (hasFoundMin) 40 { 41 cout<<0 <<endl; 42 continue; 43 } 44 sort(temp,temp+n,cmp); 45 int mini = temp[0].val; 46 for (int i=1; i<n; i++) 47 { 48 if (abs(temp[i].val) < abs(mini)) 49 { 50 mini = temp[i].val; 51 } 52 else if (abs(temp[i].val) == abs(mini) && temp[i].val > mini) 53 { 54 mini = temp[i].val; 55 } 56 } 57 for (int i=1; i<n; i++) 58 { 59 if (temp[i].val-temp[i-1].val < abs(mini)) 60 { 61 if (temp[i].index > temp[i-1].index) 62 { 63 mini = temp[i].val-temp[i-1].val; 64 } 65 else 66 { 67 mini = temp[i-1].val-temp[i].val; 68 } 69 if (mini == 0) 70 { 71 break; 72 } 73 } 74 else if (temp[i].val-temp[i-1].val == abs(mini) && mini < 0) 75 { 76 if (temp[i].index > temp[i-1].index) 77 { 78 mini = temp[i].val-temp[i-1].val; 79 if (mini == 0) 80 { 81 break; 82 } 83 } 84 } 85 } 86 cout<<mini <<endl; 87 } 88 return 0; 89 }
7 垒积木
http://ac.jobdu.com/problem.php?pid=1410
给你一些长方体的积木,问按以下规则能最多垒几个积木。
1 一个积木上面最多只能垒另一个积木。
2 在下面的积木的长宽高要大于或等于上面的积木的长宽高
输入有多组,每组输入第一行是一个整数n(1<=n<=1000000),接下来n行的每行包括三个整数l,w,h(1 <= w,l,h <= 100),表示积木的长宽高。
对于每组输入,输出按规则最多能垒几个积木。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 const int MaxNum = 100; 2 int hash[MaxNum+1][MaxNum+1][MaxNum+1]; 3 4 int func(int n) 5 { 6 memset(hash,0,sizeof(hash)); 7 int maxx=-1,maxy=-1,maxz=-1; 8 for (int i=0; i<n; i++) 9 { 10 int a,b,c; 11 scanf("%d%d%d",&a,&b,&c); 12 hash[a][b][c]++; 13 if (a>maxx) 14 { 15 maxx=a; 16 } 17 if (b>maxy) 18 { 19 maxy=b; 20 } 21 if (c>maxz) 22 { 23 maxz=c; 24 } 25 } 26 int ans = -1; 27 for (int i=1; i<=maxx; i++) 28 { 29 for (int j=1; j<=maxy; j++) 30 { 31 for (int k=1; k<=maxz; k++) 32 { 33 int tmp = 0; 34 if (i>1) 35 { 36 tmp = max(tmp,hash[i-1][j][k]); 37 } 38 if (j>1) 39 { 40 tmp = max(tmp,hash[i][j-1][k]); 41 } 42 if (k>1) 43 { 44 tmp = max(tmp,hash[i][j][k-1]); 45 } 46 hash[i][j][k] += tmp; 47 if (hash[i][j][k] > ans) 48 { 49 ans = hash[i][j][k]; 50 } 51 } 52 } 53 } 54 return ans; 55 }
8 数字在排序数组中出现的次数
http://ac.jobdu.com/problem.php?cid=1039&pid=20
(1) 给定一个有序数组a,求最小的i使得a[i]等于v,不存在则返回-1
(2) 给定一个有序数组a,求最大的i使得a[i]等于v,不存在则返回-1
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 const int MaxNum = 1000000; 2 int a[MaxNum+1]; 3 4 int getlower(int n,int x) 5 { 6 int begin=0, end=n-1; 7 int mid; 8 while(begin < end-1) 9 { 10 mid = (begin+end)/2; 11 if(a[mid] >= x) 12 { 13 end = mid; 14 } 15 else 16 { 17 begin = mid; 18 } 19 } 20 if (a[begin] == x) 21 { 22 return begin; 23 } 24 else if (a[end] == x) 25 { 26 return end; 27 } 28 else 29 { 30 return -1; 31 } 32 } 33 34 int getUpper(int n,int x) 35 { 36 int begin=0, end=n-1; 37 int mid; 38 while(begin < end-1) 39 { 40 mid = (begin+end)/2; 41 if (a[mid] <= x) 42 { 43 begin = mid; 44 } 45 else 46 { 47 end = mid; 48 } 49 } 50 if (a[end] == x) 51 { 52 return end; 53 } 54 else if (a[begin] == x) 55 { 56 return begin; 57 } 58 else 59 { 60 return -1; 61 } 62 }
9 数组中逆序的数对数目
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
http://ac.jobdu.com/problem.php?cid=1039&pid=19
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 const int INFI = 1<<30; 2 const int MaxNum = 100000; 3 int a[MaxNum+1]; 4 int leftArr[MaxNum+1]; 5 int rightArr[MaxNum+1]; 6 7 long long UnionCount(int low,int mid,int high) 8 { 9 long long ans = 0; 10 int leftNum = mid-low+1, rightNum = high-mid, totalNum = leftNum+rightNum; 11 for (int i=0; i<leftNum; i++) 12 { 13 leftArr[i] = a[low+i]; 14 } 15 leftArr[leftNum] = INFI; 16 for(int j=0; j<rightNum; j++) 17 { 18 rightArr[j] = a[mid+1+j]; 19 } 20 rightArr[rightNum] = INFI; 21 int i = 0, j = 0; 22 for (int k=0; k<totalNum; k++) 23 { 24 if (leftArr[i] <= rightArr[j]) 25 { 26 a[low+k] = leftArr[i++]; 27 } 28 else 29 { 30 ans += leftNum-i; 31 a[low+k] = rightArr[j++]; 32 } 33 } 34 return ans; 35 } 36 37 long long func(int low,int high) 38 { 39 long long ans = 0; 40 if (low < high) 41 { 42 int mid = low + (high-low)/2; 43 ans += func(low,mid); 44 ans += func(mid+1,high); 45 ans += UnionCount(low,mid,high); 46 } 47 return ans; 48 }
10 最小的K个数
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
http://ac.jobdu.com/problem.php?cid=1039&pid=13
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #include <iostream> 2 #include <algorithm> 3 #include <set> 4 #include <stack> 5 #include <queue> 6 #include <vector> 7 #include <iterator> 8 #include <cmath> 9 #include <sstream> 10 #include <cstring> 11 #include <stdio.h> 12 #include <list> 13 #include <map> 14 #include <iomanip> 15 #include <assert.h> 16 #include <string> 17 #include <time.h> 18 19 using namespace std; 20 21 int a[200001]; 22 23 inline void swap(int &a, int &b) 24 { 25 int t = a; 26 a = b; 27 b = t; 28 } 29 30 int myPartition(int low,int high) 31 { 32 int mid = low; 33 int ran = low + rand()%(high-low+1); 34 swap(a[ran],a[high]); 35 int pivot = a[high]; 36 for (int j=low; j<high; j++) 37 { 38 if (a[j] < pivot) 39 { 40 swap(a[mid],a[j]); 41 mid++; 42 } 43 } 44 swap(a[mid],a[high]); 45 return mid; 46 } 47 48 void func(int k,int low,int high) 49 { 50 if (low < high) 51 { 52 int mid = myPartition(low,high); 53 int num = mid-low+1; 54 if (num == k) 55 { 56 return; 57 } 58 else if (num > k) 59 { 60 func(k,low,mid-1); 61 } 62 else 63 { 64 func(k-num,mid+1,high); 65 } 66 } 67 } 68 69 70 int main() 71 { 72 int n,k; 73 while(scanf("%d%d",&n,&k) != EOF) 74 { 75 for (int i=0; i<n; i++) 76 { 77 scanf("%d",&a[i]); 78 } 79 if (k >= n) 80 { 81 sort(a,a+n); 82 } 83 else 84 { 85 func(k,0,n-1); 86 sort(a,a+k); 87 } 88 int mini = (n>k?k:n); 89 printf("%d",a[0]); 90 for (int i=1; i<mini; i++) 91 { 92 printf(" %d",a[i]); 93 } 94 printf("\n"); 95 } 96 return 0; 97 }
11 最近点对
http://acm.hdu.edu.cn/showproblem.php?pid=1007
给n个点的坐标,求距离最近的一对点之间距离的一半。第一行是一个数n表示有n个点,接下来n行是n个点的x坐标和y坐标,实数。
主要思想就是分治。先把n个点按x坐标排序,然后求左边n/2个和右边n/2个的最近距离,最后合并。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 const int MaxNum = 100000; 2 int temp[MaxNum+1]; 3 struct Pt 4 { 5 double x,y; 6 }; 7 Pt a[MaxNum+1]; 8 9 bool cmpx(Pt p1,Pt p2) 10 { 11 return p1.x < p2.x; 12 } 13 14 bool cmpy(int y1,int y2) 15 { 16 return a[y1].y < a[y2].y; 17 } 18 19 double compute(const Pt & p1,const Pt & p2) 20 { 21 return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); 22 } 23 24 double func(int low,int mid,int high,double minDist) 25 { 26 int cnt = 0; 27 for (int i=low; i<=high; ++i) 28 { 29 if (abs(a[i].x-a[mid].x) <= minDist) 30 { 31 temp[cnt++] = i; 32 } 33 } 34 sort(temp,temp+cnt,cmpy); 35 for (int i=0; i<cnt; ++i) 36 { 37 int k = min(i+7,cnt); 38 for (int j=i+1; j<k; ++j) 39 { 40 if (a[temp[j]].y - a[temp[i]].y > minDist) 41 { 42 break; 43 } 44 minDist = min(minDist,compute(a[temp[j]],a[temp[i]])); 45 } 46 } 47 return minDist; 48 } 49 50 double closest(int low,int high) 51 { 52 if (low+1 == high) 53 { 54 return compute(a[low],a[high]); 55 } 56 else if (low+2 == high) 57 { 58 return min(compute(a[low],a[low+1]),min(compute(a[low+1],a[low+2]),compute(a[low],a[low+2]))); 59 } 60 else 61 { 62 int mid = low + (high-low)/2; 63 double ans = min(closest(low,mid),closest(mid+1,high)); 64 double t = func(low,mid,high,ans); 65 ans = min(ans,t); 66 return ans; 67 } 68 } 69 70 int main() 71 { 72 int n; 73 while(scanf("%d",&n) != EOF && n!=0) 74 { 75 for (int i=0; i<n; ++i) 76 { 77 scanf("%lf%lf",&a[i].x,&a[i].y); 78 } 79 sort(a,a+n,cmpx); 80 printf("%.2lf\n",closest(0,n-1)/2); 81 } 82 return 0; 83 }
12 最长递增子序列
题意:求一个数组中最长递增子序列的长度。要求选择该题最好算法的时间复杂度和空间复杂度。答案:时间复杂度O(NlgN),空间复杂度O(N)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 const int MaxNum = 500000; 2 int a[MaxNum+1]; 3 int lis[MaxNum+1]; 4 int MaxV[MaxNum+1]; 5 6 int minArray(int *pArray,int n) 7 { 8 int ans = pArray[0]; 9 for (int i=1; i<n; i++) 10 { 11 if (pArray[i] < ans) 12 { 13 ans = pArray[i]; 14 } 15 } 16 return ans; 17 } 18 19 int backFindFirstMin(int *pArray,int n,int x) 20 { 21 int low = 0, high = n-1; 22 int mid; 23 while(low <= high) 24 { 25 mid = low + (high-low)/2; 26 if (pArray[mid] >= x) 27 { 28 high = mid-1; 29 } 30 else 31 { 32 low = mid+1; 33 } 34 } 35 return high; 36 } 37 38 int func(int *pArray,int n) 39 { 40 MaxV[0]=minArray(pArray,n); 41 MaxV[1]=pArray[0]; 42 int ans = 1; 43 for (int i=0; i<n; i++) 44 { 45 lis[i]=1; 46 } 47 for (int i=1; i<n; i++) 48 { 49 int j=backFindFirstMin(pArray,ans+1,a[i]); 50 lis[i] = j+1; 51 if (lis[i] > ans) 52 { 53 ans = lis[i]; 54 MaxV[ans] = a[i]; 55 } 56 else if (a[i] > MaxV[j] && a[i]<MaxV[j+1]) 57 { 58 MaxV[j+1] = a[i]; 59 } 60 } 61 return ans; 62 }
13 编程实现两个正整数的除法,不能用除法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 int divide(int x,int y) 2 { 3 int remain = x,ans = 0; 4 while(remain >= y) 5 { 6 int tmp = 1; 7 while(y*tmp <= (remain>>1)) 8 { 9 tmp <<= 1; 10 } 11 ans += tmp; 12 remain -= y*tmp; 13 } 14 return ans; 15 }
14 给定一个函数rand5(),该函数可以随机生成1-5的整数,且生成概率一样。现要求使用该函数构造函数rand7(),使函数rand7()可以随机等概率的生成1-7的整数。
利用rand5()函数生成1-25之间的数字,然后将其中的1-21映射成1-7,丢弃22-25。这种思想是基于,rand()产生[0,N-1],把rand()视为N进制的一位数产生器,那么可以使用rand()*N+rand()来产生2位的N进制数,以此类推,可以产生3位,4位,5位...的N进制数。这种按构造N进制数的方式生成的随机数,必定能保证随机,而相反,借助其他方式来使用rand()产生随机数(如 rand5() + rand5()%3 )都是不能保证概率平均的。此题中N为5,因此可以使用rand5()*5+rand5()来产生2位的5进制数,范围就是1到25。再去掉22-25,剩余的除3,以此作为rand7()的产生器。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 int rand7() 2 { 3 int x = 0; 4 do 5 { 6 x = 5 * (rand5() - 1) + rand5(); 7 } 8 while(x > 21); 9 return 1 + x%7; 10 }
给定一个函数rand()能产生0到n-1之间的等概率随机数,问如何产生0到m-1之间等概率的随机数?
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 int randm(int m , int n) 2 { 3 int k = randn(); 4 int max = n-1; 5 while(k < m) 6 { 7 k = k*n + randn(); 8 max = max*n + n-1; 9 } 10 return k/(max/(m-1)); 11 }