一、一些常规的算法

1、对于一个字节(8bit) 的无符号整型变量,求其二进制表示中“1”的个数。

要求算法的执行效率尽可能高。

#include<stdio.h>
int count1(int x)  //法1 
{
	int num = 0;
	while(x)
	{
		if(x&1 == 1)   num++;  //按位与运算,x&1的结果就是取x二进制的最末位,
		                    	//即可以判断x是奇数还是偶数 
		x = x>>1;  //右移1位,相当于/2
	}
	return num;
}
int count2(int x)  //法2 
{
	int num = 0;
	while(x)
	{
		x = x & (x-1);  //对于任意整数x,令x=x&(x-1),
						//该运算将x的二进制表示的最后一个1变成0 
		num++;
	}
	return num;
}
int main()
{
	int x, y;
	printf("Please input a number:");
    scanf("%d", &x);
//	y = count1(x);
	y = count2(x);
	printf("The number of 1 in the binary number is %d", y);
	return 0;
}

2、给定一个整数N,N!末尾会有多少个0呢?编写算法计算给定的N!末尾有多少个0?

例如:N=10,N!=3628800,N!末尾有2个0。
#include<stdio.h>
//末尾有多少个0 =》找有多少个5 
int count0(int x)  //法1 
{
	int n = 0;
	while(x != 0)
	{
		n = n + x/5;
		x = x/5;
	}
	return n;
}
int count1(int x)  //法2:递归 (递归会慢一些)
{
	int n = 0, n1 = 0, n2 = 0;
	n1 = x/5;
	if(n1 > 0)
		n2 = count1(n1);		
	n = n1 + n2;
	return n;
}
int main()
{
	int x, n = 0;
	printf("Please input a number: ");
	scanf("%d", &x);
	n = count0(x);
//	if(x > 0)
//		n = count1(x);
	printf("The number of 0 in tail is %d", n);
}

//大整数加法,大整数乘法

3、求N!的二进制表示中最低位的1的位置。(跟第2题类似,即找二进制末尾有几个0)

即找2的个数

#include<stdio.h>
int count1(int x)  //法1 
{
	int n = 0;
	while(x != 0)
	{
		n = n + x/2;
		x = x/2;
	}
	return n;
}

int main()
{
	int x, n = 0;
	printf("Please input a number: ");
	scanf("%d", &x);
	n = count1(x);
	printf("The inverted index of the lowest 1 is %d\n", n+1);
}

4、找出数组中的最大值、最小值

对于一个由N个整数组成的数组,设计算法(程序),求出该数组中的最大值和最小值。
要求尽可能少的元素值比较次数。
你能想到多少种解决方法?给出尽可能多的解决方案,分析每个方案的元素值比较次数。
方法:
1.正常比: 2n-2 全部比较一次
2.奇偶位比较:3n/2 -2 循环一次比较两个数,奇偶位比较
3.二分法: 3n/2 -2

分治法解题的一般步骤:(递归的思想)
(1)分解,将要解决的问题划分成若干规模较小的同类问题;
(2)求解,当子问题划分得足够小时,用较简单的方法解决;
(3)合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。

二分法在求最值上的应用算法思想:
void maxmin2(int A[],int i,int j,int *max,int *min)
//A存放输入的数据,i,j存放数据的范围,初值为0,n-1,*max,*min 存放最大和最小值
{
    int mid,max1,max2,min1,min2;
    if (j==i)
    {
        最大和最小值为同一个数;
        return;
    }
    if (j-1==i)
    {
        将两个数直接比较,求得最大和最小值;
        return}
    mid=(i+j)/2;
    求i~mid之间的最大最小值分别为max1,min1;
    求mid+1~j之间的最大最小值分别为max2,min2;
    比较max1和max2,大的就是最大值;
    比较min1和min2,小的就是最小值;
}
#include<stdio.h>
void compare(int *a, int n, int * max, int * min)   //2.奇偶位比较:注意需要判断数组长度是奇数还是偶数
{
	*min = a[0];  
	*max = a[1]; 
	int i;
	if(n%2 == 0)  //数组元素个数为偶数
	{
		for(i = 2; i < n-1; i = i + 2)
		{
			if(a[i] < a[i+1])
			{
				if(a[i] < *min)
					*min = a[i];
				if(a[i+1] > *max)
					*max = a[i+1];
			}
			else
			{
				if(a[i+1] < *min)
					*min = a[i+1];
				if(a[i] > *max)
					*max = a[i];
			}
		}	
	}
	else  //数组元素个数为奇数
	{
		for(i = 2; i < n-1; i = i + 2)
		{
			if(a[i] < a[i+1])
			{
				if(a[i] < *min)
					*min = a[i];
				if(a[i+1] > *max)
					*max = a[i+1];
			}
			else
			{
				if(a[i+1] < *min)
					*min = a[i+1];
				if(a[i] > *max)
					*max = a[i];
			}
		}
		//奇数在最后会多出一位,单独进行比较
		if(a[n-1] < *min)
			*min = a[n-1];
		if(a[n-1] > *max)
			*max = a[n-1];
	}	
}

void compare1(int *a, int n, int * max, int * min)  //1.正常比:所有元素全部比较一次
{
	*min = a[0];  
	*max = a[1];    
	int i;
	for(i = 2; i < n; i++)
	{
		if(a[i] < *min)
			*min = a[i];
		if(a[i] > *max)
			*max = a[i];			
	}
}

void search_max_and_min_value(int *array, int index_begin, int index_end, int* max, int* min)  //3.二分法
{
	//非法输入
    if(array == NULL || max == NULL || min == NULL)	return;
    if(index_begin > index_end)	return;

    /// the minimum array comparison
    if (index_end - index_begin <= 1)   //递归出口
	{	  
        if (array[index_end] < array[index_begin]) 
		{
            *max = array[index_begin];
            *min = array[index_end];
        } 
		else 
		{
            *min = array[index_begin];
            *max = array[index_end];
        }
        return;
    }

    /// divide array to small problem
    int middle = index_begin + (index_end - index_begin) / 2;
    int max_left, max_right, min_left, min_right;
	//递归
    search_max_and_min_value(array, index_begin, middle, &max_left, &min_left);
    search_max_and_min_value(array, middle + 1, index_end, &max_right, &min_right);

    /// conquer the small problem
    if (max_left > max_right)
        *max = max_left;
    else
        *max = max_right;
    if (min_left < min_right)
        *min = min_left;
    else
        *min = min_right;
    return;
}


int main()
{
	int a[10] = {3,1,3,1,3,5,8,2,2};
	int n = 9;
	int max , min;
	compare(a, n, &max, &min);
	printf("min: %d , max: %d\n", min, max);
	compare1(a, n, &max, &min);
	printf("min: %d , max: %d\n", min, max);
	search_max_and_min_value(a, 0, n-1, &max, &min);
	printf("min: %d , max: %d\n", min, max);
}

5、快速找出数组中和为sum的数

快速找出一个数组中所有满足条件的的两个数。
(条件:这两个数的和等于一个给定的值sum.)
为了简化,我们假设这个数组中肯定存在至少一组符合要求的解。
给出尽可能多的解决方法,并分析每种方法的效率。
方法:
1.穷举O(N^2)
2.求两数之和=》已知一个数找另外一个数
key从数组头依次指向数组尾
1)折半查找O(Nlog2N)
2)哈希查找O(N)空间复杂度:S(N)
3.先将数组排序,在用两个指针分别从表头表尾出发,向内边走边查
令i = 0,j = n-1,看arr[i] + arr[j] 是否等于Sum,如果是,i++; j–;继续查找。
如果小于Sum,则i = i + 1;如果大于Sum,则 j = j – 1。
这样只需要在排好序的数组上遍历一次,就可以得到最后的结果,时间复杂度为O(N)。
两步加起来总的时间复杂度O(N
log2N)

下面利用方法3解决该问题。

#include<iostream>
#include<algorithm>
using namespace std;

int findNumber(int a[], int n, int sum, int number[][2])
{
	sort(a, a+n-1);
	int i=0, j=n-1, k=0;
	while(i < j)
	{
		while(i<j && a[i]+a[j] == sum)
		{
			number[k][0] = a[i];
			number[k][1] = a[j];
			k++;
			i++; j--;
		}
		while(i<j && a[i]+a[j] < sum)
			i++;
		while(i<j && a[i]+a[j] > sum)
			j--;
	}
	return k;
}

void main()
{
	int a[8] = {4,5,1,6,2,7,3,8};
	int n = 8, sum = 7, num;
	int number[8][2];
	int i,j;
	for(i = 0; i < n; i++)
		for(j = 0; j < 2; j++)
			number[i][j] = 0;
	num = findNumber(a, n, sum, number);
	for(i = 0; i < num; i++)
	{
		for(j = 0; j < 2; j++)
			cout<<number[i][j]<<" ";
		cout<<endl;
	}	
}

6、大整数加法

输入数字n,按顺序打印输出从1到最大的n位十进制数。比如输入3,则打印出1,2,3,一直到最大的3位数999.
要考虑若n很大,我们求最大的n位数用int 或long long 也可能会溢出。
考虑大数问题;
提示:关于大数的表示和存储:用字符数组(取值为数字型字符)来表达大数。

方法:
1.每一次输出+1
2.全排列,递归: 频繁地入栈出栈,占用内存资源。

注意:
数组使用前要初始化
输入n后,我们指定数组的长度为n+1(因为考虑到进位)
思路:
数组从左向右依次+1,若进位,则向右进一位,最后逆序输出。
tips:
C++中未初始化的数组的默认值问题
1.全局数组,未初始化时,默认值都是 0;
2.局部数组,未初始化时,默认值为随机的不确定的值;
3.局部数组,初始化一部分时,未初始化的部分默认值为 0;

#include<iostream.h>

void add1(int a[],int n)  //+1运算,将其看作大整数加法,加数为1
{
	int i;
	int *one = new int[n+1];  //将1也设为数组,其长度为n+1
	one[0] = 1;               //初始化
	for(i = 1; i < n+1; i++)
		one[i] = 0;

	for(i = 0; i < n; i++)  //每一位对应相加
	{
		a[i] = a[i] + one[i];
		if(a[i] >= 10)  //进位
		{
			a[i] = a[i] - 10;
			a[i+1]++;
		}
	}
}

void bigNumber(int a[], int n)
{
	int i, j;
	while(a[n]==0)  //终止条件
	{
		add1(a, n);
		if(a[n] == 0)
		{
			for(i = n; a[i] == 0; i--);	//从右向左,找到第一个不为0的数。
			for(j = i; j >= 0; j--)  //逆序输出每一位
				cout<<a[j];
			cout<<" ";
		}	
	}	
}

void main()
{
	int n = 1, i;
	cout<<"n = ";
	cin>>n;
	int* a = new int[n+1];
	for(i = 0; i < n+1; i++) //初始化数组
		a[i] = 0;
	bigNumber(a, n);
	cout<<endl;
}

7.快速找出x在二维数组中的位置

设二维数组B[0…m-1][0…n-1]的数据在行、列方向上都按从小到大的顺序有序,
且x在B中存在。试设计一个算法,找出x在B数组中的位置i, j。要求比较的次数不超过m+n.

思想: 因为数据在行、列方向上都按从小到大的顺序有序,所以可以只比较一列,
在这里我们只比较最后一列,因为是从上向下比,所以该数如果比某一行最后一列小,那么该数一定在该行上。

#include <iostream>
using namespace std;

bool position(int** number, int m, int n, int x, int &p, int &q)
{
    int i, j;
    bool tag = false;
    if (x < number[0][0] || x > number[m-1][n-1])   //非法数
        return tag;
    else
    {
        for (i = 0; i < m; i++)
        {
            if (x == number[i][n-1])    //如果该数就在最后一列上,直接返回
            {
                p = i; q = n-1;
                tag = true;
                break;
            }
            else if (x < number[i][n-1])    //如果比某一行的最后一列小,即找到该行,跳出循环
                break;
        }
        if (x < number[i][n - 1])   //在改行上遍历寻找
        {
            for (j = 0; j < n-1; j++)
            {
                if (x == number[i][j])
                {
                    p = i;  q = j;
                    tag = true;
                    break;
                }
            }
        }
        return tag;
    }
}

int main()
{
    int i, j, m=4, n=4, a = 1;
    int x;
    bool tag;
    int** number = new int* [m];
    for (i = 0; i < m; i++)
    {
        number[i] = new int[n];
        for (j = 0; j < n; j++)
        {
            number[i][j] = a;
            a++;
        }
    }
    for (i = 0; i < m; i++)
    {
        for (j = 0; j < n; j++)
        {
            cout.width(3);
            cout<<number[i][j]<<" ";
        }        
        cout << endl;
    }
        
    cout << endl;
    cout << "x = ";
    cin >> x;
    i = 0; j = 0;
    tag = position(number, m, n, x, i, j);
    if (tag == true)
        cout << "i = " << i << ", j = " << j << endl;
    else
        cout << "没有找到x" << endl;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值