在路上遇见的一些算法问题

在每天码代码的过程中,有时候会遇见一些比较经典的算法问题。我想总结一下最近遇见的一下算法。

 

问题:

有一个桶,里面有白球和黑球各100个,规则如下:

  1. 每次随机从桶中取出两个球
  2. 如果是两个同色的球,就再放入一个黑球
  3. 如果是两个异色的球,就再放入一个白球

问:最后桶中只剩下一个黑球的概率是多少?(白球数不管)

答:

我们可一个用一个set(黑球数量,白球数量)来表示桶中的黑球和白球的个数。从桶中取出球后,只可能是下列三种操作:

  1.取出的是两个黑球,则放回一个黑球:(-2, 0) + (1, 0) = (-1, 0)

  2.取出的是两个白球,则放回一个黑球:(0, -2) + (1, 0) = (1, -2)

  3.取出的是一黑一白,则放回一个白球:(-1, -1) + (0, 1) = (-1, 0)

根据上面的规则,我们可以发现:白球的数量变化情况只能是不变或者-2,也就是说,如果是100个白球,白球永远不可能是1个的情况,那么问题的解法就很简单了,就是只剩下黑球的概率为100%。

 

问:给你一个自然数N,求【6,N】之内所有素数中两两之和为偶数的那些偶数。

用哥德巴赫猜想(欧拉版):任一大于2的偶数都可写成两个质数之和

答:故只需列出所有偶数即可。[6,N]的素数之和最小偶数为14(允许相同素数的情况下),最大偶数为最大素数的2倍。

 

问:有一种毒药,猪喝了15分钟内会死亡(假设猪喝水不花费时间,而且不是定时死亡)。现在我们有1000桶水,需要用猪去测出哪桶水有毒,需要几头猪?

答:使用数列(五维空间)方法,5头。

 

问:排序方法有哪些?

答:

1.冒泡

void BubbleSort(int arr[],int count)
{
    int temp=0;
    bool swapped=false;
    for(int i=1;i<count;i++)
    {
        swapped=false;
        for(int j=count-1;j>=i;j--)
        {
            if(arr[j-1]>arr[j])
            {
                temp=arr[j-1];
                arr[j-1]=arr[j];
                arr[j]=temp;

            }
            swapped=true;
        }

        if(!swapped)//本趟排序未发生交换,提前终止算法
            return;
    }
}

2.二分查找

int BinSearch(int *arr, int n , int key)
{
    int low = 0;
    int high = n-1;
    int mid;              
    if(arr[low] == key)
    {
        return 0;
    }

    while(low <= high)
    { 
        mid = low + ((high - low)/2);
        if(arr[mid] == key)
        {
            return mid;
        }

        if(arr[mid] > key)
            high = mid - 1; 
        else
            low = mid + 1;
    }
    return -1;
}

3.快排

#include <stdio.h>
int a[100] = { 1, 2, 8, 7, 9, 5, 6, 4, 3, 66, 77, 33, 22, 11 };
 
/* 输出数组前n各元素*/
void prt(int n) {
    int i;
    for (i = 0; i < n; i++) {
        printf("%d\t", a[i]);
    }
    printf("\n");
}
 
/* 数据交换*/
void swap(int *a, int *b)
{
    int tmp;
    tmp = *a; *a = *b; *b = tmp;
}
 
void quick_sort(int a[], int left, int right)
{
    int i = left + 1, j = right;
    int  key = a[left];
 
    if (left >= right) return;
 
    /* 从i++和j--两个方向搜索不满足条件的值并交换 *
     * 条件为:i++方向小于key,j--方向大于key      */
    while (1) {
       while (a[j] > key) j--;
       while (a[i] < key&&i<j) i++;
       if(i >= j) break;
       swap(&a[i],&a[j]);
       if(a[i]==key)j--;
       else  i++;
    }
 
    /* 关键数据放到‘中间’*/
    swap(&a[left],&a[j]);
 
    if(left  < i - 1)   quick_sort(a, left, i - 1);
    if(j + 1 < right)  quick_sort(a, j + 1 , right);
 
}
 
int main(void) {
 
    /* 排序与输出*/
    quick_sort(a, 0, 13);
    prt(14);
 
    return 0;
}

 

问:101个硬币中有一个假币,有一个无砝码的天平,称两次,判断假币比真币重还是轻。

答:

方案1:把101个硬币平均分成三份,分别是:33,33,35,把两 堆33个放在天平上称。
1、如果平衡,说明这66个都是真的。然后从这两堆共66个中取出35个,与第三堆的35个分别放在天平的左右盘中称,这样,第三堆所在的天平的那一端的轻重就是假币的轻重情况。

2、如果两 个33放在天平上不平衡,说明第三堆的35个是真的。取下轻的一端的33个,从第三堆中取33个放在上面,如果平衡,说明取下的一堆中有假币,假币比真的轻。如果不平衡,只有一种结果,第三堆与取下的一堆一样,都比那一堆轻,说明假的比真的重。

方案2:将硬币按A组(50)、B组(50)、C组(1)分组,先比较A、B两组:

    1>.若A=B,则C为假币,再用A或B中任一个与C比,C重则假币重,C轻则真币重

    2>.若A!=B,则A或B中含假币,将A组一分为二:A1(25)、A2(25),比较A1、A2:

       <1>.若A1=A2,则A为真币,故:A>B => 真币重;A<B => 假币重

       <2>.若A1!=A2,则A含假币,故:A<B => 真币重;A>B => 假币重

 

问:有一把手枪(无线子弹),当第一个人拿到手枪会打死旁边的人,然后将手枪传下去。1000个人拿着手枪围着圈坐在一起,请问最后存活的是第几个人?

答:第977个    【n-2^j】* 2+1;

java实现

public class NewtonMethod {

	public static void main(String[] args) {

		Scanner scanner=new Scanner(System.in);
		System.out.println("请输入参与人数");
		String scan=scanner.next();
		int a=Integer.parseInt(scan);
		NewtonMethod  newtonMethod = new NewtonMethod();
		//int x = newtonMethod.sqrt(2);
		int o = newtonMethod.HA(a);
		System.out.println("幸运人数是第"+o+"位");
		//System.out.print(x);
	}

	public int HA(int n)
	{
		int k=0;
		for( double i=0;Math.pow(2,i)<n;i++)
		{
			double sum=(n-Math.pow(2,i))*2+1;
			k = (int)sum;
		}
		
		return k;
		
	}}

 

问:从最多10个整数的集合中,分成两组(不需平均分组,可以一组1个、另一组9个),要求只要两组的总和差值最小,还有就是集合里的数量可奇可偶。

答:

public class RandomlyAssigned {

	public static void main(String[] args) {
                // 从大到小排好序的数组
                int arr[]={100,91,81,77};
		List<Integer> sum1=new ArrayList<Integer>();
		List<Integer> sum2=new ArrayList<Integer>();
		int a=0;
		int b=0;
		for(int i=0;i<arr.length;i++){
			if(a<=b){
				sum1.add(arr[i]);
				a+=arr[i];
			}else{
				sum2.add(arr[i]);
				b+=arr[i];
			}
		}
		System.out.println("A:" + sum1 + ", B: " + sum2 + ", 差值:" + Math.abs(a - b));
	}
}

升级版

package com.Test.method;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

/**
 * @author Sakura
 * @function 分组选出差值最小的两组
 * @date 2018-12-7
 * @modify date ,modify author,modify cause
 *
 */
public class RandomlyAssigned {

	public static void main(String[] args) {
		System.out.print("请输入您要分配的数组长度和数组 如:3组   分别是 1 2 3\n");
		Scanner scanner = new Scanner(System.in);
		while (scanner.hasNext()) {
			int m = scanner.nextInt();
			int[] arr = new int[m];
			for (int i = 0; i < m; i++) {
				arr[i] = scanner.nextInt();
			}
			System.out.print("您输入的数组是:\n" + Arrays.toString(arr) + "\n");
			RandomlyAssigned RanASS = new RandomlyAssigned();
			RanASS.BubbleSort(arr, m);
			RanASS.Random(arr);
		}
	}

	public void BubbleSort(int arr[], int count) {
		int temp = 0;
		boolean swapped = false;
		for (int i = 1; i < count; i++) {
			swapped = false;
			for (int j = count - 1; j >= i; j--) {
				if (arr[j - 1] < arr[j]) {
					temp = arr[j - 1];
					arr[j - 1] = arr[j];
					arr[j] = temp;

				}
				swapped = true;
			}
		}
		System.out.print("由大到小排列后:\n" + Arrays.toString(arr) + "\n");
	}

	public void Random(int arr[]) {
		int sum1 = 0;
		int sum2 = 0;
		List<Integer> group1 = new ArrayList<Integer>();
		List<Integer> group2 = new ArrayList<Integer>();
		for (int i = 0; i < arr.length; i++) {
			if (sum1 <= sum2) {
				group1.add(arr[i]);
				sum1 += arr[i];
			} else {
				group2.add(arr[i]);
				sum2 += arr[i];
			}
		}
		System.out.println("分组后为:\n" + "A:" + group1 + ", B: " + group2
				+ "\n 差值:" + Math.abs(sum1 - sum2));

	}
}

 

转载于:https://my.oschina.net/aidaidai/blog/2980496

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值