经典算法题目

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。

View Code
 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。判断数组中是否有重复的数字。(原数组不必保留)

View Code
 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 写一个函数,求两个整数的之和,要求在函数体内不得使用+、-、×、÷。

View Code
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

View Code
 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

View Code
 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

View Code
 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),表示积木的长宽高。

对于每组输入,输出按规则最多能垒几个积木。

View Code
 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

View Code
 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

View Code
 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

View Code
 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个的最近距离,最后合并。

View Code
 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)。

View Code
 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  编程实现两个正整数的除法,不能用除法

View Code
 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()的产生器。

View Code
 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之间等概率的随机数?

 

View Code
 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 }  

 

 

 

转载于:https://www.cnblogs.com/shenshanxiaoyao/archive/2012/10/03/2710974.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值