基于二分查找的抽签游戏算法的优化

  基于二分查找的抽签游戏算法的优化

问题描述:

一个袋子里有n个纸片,纸片上有数字,你随机取出4张纸(有放回),若四张纸的数字和为m,你就赢了,否则你就输了。连续试了几次后你都失败了,于是你想知道到底有没有赢的例子。(n:1到50; m和k[i] 1到10的8次方)

输入输出样例:

输入:

n=3

m=10

k={1,3,5}

输出:yes(1+1+3+5=10)

输入

n=3

m=9

k={1,3,5}

输出:

No

复杂度为N的四次方

复杂度为N的四次方算法分析:

通过四重循环来枚举所有情况。

复杂度为N的四次方算法实现:

package com.renyou.算法;

import java.util.Scanner;
/**
 * m=k[a]+k[b]+k[c]+k[d]
 * @author 刘仁有
 * (10的8次方=>m=>1)
 *  (50=>n>=1)
 *  (10的8次方=>k[i]=>1)
 *  
 */
public class 抽签复杂度N的4次方 {
	private final int MAX_N=50;
	public static void main(String[] args) {
         new 抽签复杂度N的4次方().抽签();
 	}
	public void 抽签(){
		int m,n;
		int[] k;
		Scanner scanner=new Scanner(System.in);
		m=scanner.nextInt();
		n=scanner.nextInt();
		k=new int[n];
		for(int i=0;i<n;i++){
			k[i]=scanner.nextInt();
		}
        
		for(int a=0;a<n;a++){
			for(int b=0;b<n;b++){
				for(int c=0;c<n;c++){
					for(int d=0;d<n;d++){
						if(k[a]+k[b]+k[c]+k[d]==m)
						System.out.println("找到了这四个值,分别是:"+k[a]+";"+k[b]+";"+k[c]+";"+k[d]);
						
					}
				}
			}
		}
	}
}


复杂度为N的三次方LogN

复杂度为N的三次方LogN的算法分析:

检查是否有k[d]使得k[d]=m-k[a]-k[b]-k[c]

复杂度为N的三次方LogN的算法实现:

package com.renyou.算法;

import java.util.Scanner;


/**
 * k[d]=m-k[a]-k[b]-k[c]
 * @author 刘仁有 (10的8次方=>m=>1) (1000=>n>=1) (10的8次方=>k[i]=>1)
 * 
 */
public class 抽签复杂度N的三次方LogN {
	private final int MAX_N = 1000;
	private int[] k ;

	public static void main(String[] args) {
		new 抽签复杂度N的三次方LogN().抽签();
	}

	public void 抽签() {
		int m, n;

		/******** 控制台输入数据 **********/
		Scanner scanner = new Scanner(System.in);
		m = scanner.nextInt();
		n = scanner.nextInt();
		k=new int[n];
		for (int i = 0; i < n; i++) {
			k[i] = scanner.nextInt();
		}
		/********** 数组快速排序 **************/
		sort(k, 0, k.length - 1);

		/*********** N的三次方的for循环 ***************/
		for (int a = 0; a < n; a++) {
			for (int b = 0; b < n; b++) {
				for (int c = 0; c < n; c++) {
					if(bineary_search(m-k[a]-k[b]-k[c])){
						System.out.println("找到了这四个值,分别是:"+k[a]+";"+k[b]+";"+k[c]+";"+(m-k[a]-k[b]-k[c]));
					}
				}
			}
		}
	}

	/**
	 * 
	 * @param 要查找的值
	 * @return ture or false
	 */
	public boolean bineary_search(int value) {
		int low = 0;
		int high = k.length - 1;
		while (low <= high) {
			int mid = (low + high) / 2;
			int midValue = k[mid];
			if (value < midValue) {
				high = mid - 1;
			} else if (value > midValue) {
				low = mid + 1;
			} else {
				return true;
			}
		}
		return false;
	}

	/**
	 * 快速排序
	 * 
	 * @param array
	 *            待快速排序数组
	 * @param first
	 *            待快速排序序列的最左边所在位置
	 * @param end
	 *            待快速排序序列的最右边所在位置
	 */
	public void sort(int[] array, int first, int end) {
		int pivot = 0;// 轴值记录所在位置
		if (first < end) {// 区间长度大于一才会执行一次划分,否则递归结束
			pivot = partition(array, first, end);// 进行一次划分
			sort(array, first, pivot - 1);// 递归地对左序列进行快速排序
			sort(array, pivot + 1, end);// 递归地对右序列进行快速排序
		}
	}

	/**
	 * 快速排序一次划分算法
	 * 
	 * @param array
	 *            待快速排序数组
	 * @param first
	 *            待快速排序序列的最左边所在位置
	 * @param end
	 *            待快速排序序列的最右边所在位置
	 * @return 每次划分序列轴值最后记录所在位置
	 */
	public int partition(int[] array, int first, int end) {

		while (first < end) {
			while (first < end && array[first] <= array[end]) {// 右侧扫描
				end--;
			}
			if (first < end) {
				swap(array, first, end);
				first++;
			}

			while (first < end && array[first] <= array[end]) {// 左侧扫描
				first++;
			}
			if (first < end) {
				swap(array, end, first);
				end--;
			}
		}
		return first;
	}

	/**
	 * 
	 * @param array
	 *            待交换数组
	 * @param i
	 *            待交换数组的一个索引
	 * @param j
	 *            待交换数组的另一个索引
	 */
	public void swap(int[] array, int i, int j) {
		int temp = array[i];
		array[i] = array[j];
		array[j] = temp;
	}
}


复杂度为N的二次方LogN

复杂度为N的二次方LogN的算法分析:


检查是否有k[c]+k[d]使得k[c]+k[d]=m-k[a]-k[b]

复杂度为N的二次方LogN的算法实现:

package com.renyou.算法;

import java.util.Scanner;

/**
 * k[c]+k[d]=m-k[a]-k[b]
 * 
 * @author 刘仁有 (10的8次方=>m=>1) (1000=>n>=1) (10的8次方=>k[i]=>1)
 * 
 */
public class 抽签复杂度N的二次方LogN {
	private final int MAX_N = 1000;
	private int[] k;
	private int[] kcd;// 存储 c和d的和的数组

	public static void main(String[] args) {
		new 抽签复杂度N的二次方LogN().抽签();
	}

	public void 抽签() {
		int m, n;

		/******** 控制台输入数据 **********/
		Scanner scanner = new Scanner(System.in);
		m = scanner.nextInt();
		n = scanner.nextInt();
		k = new int[n];
		for (int i = 0; i < n; i++) {
			k[i] = scanner.nextInt();
		}

		/*********** 存储 c和d的和 **********/
		kcd = new int[n * n];
		for (int c = 0; c < n; c++) {
			for (int d = 0; d < n; d++) {
				kcd[c * n + d] = k[c] + k[d];
			}
		}
		/********** kcd数组快速排序 **************/
		sort(kcd, 0, kcd.length - 1);

		/*********** N的三次方的for循环 ***************/
		for (int a = 0; a < n; a++) {
			for (int b = 0; b < n; b++) {

				if (bineary_search(m - k[a] - k[b])) {
					System.out.println("找到了这四个值");
				}
			}
		}

	}

	/**
	 * 
	 * @param 要查找的值
	 * @return ture or false
	 */
	public boolean bineary_search(int value) {
		int low = 0;
		int high = kcd.length - 1;
		while (low <= high) {
			int mid = (low + high) / 2;
			int midValue = kcd[mid];
			if (value < midValue) {
				high = mid - 1;
			} else if (value > midValue) {
				low = mid + 1;
			} else {
				return true;
			}
		}
		return false;
	}

	/**
	 * 快速排序
	 * 
	 * @param array
	 *            待快速排序数组
	 * @param first
	 *            待快速排序序列的最左边所在位置
	 * @param end
	 *            待快速排序序列的最右边所在位置
	 */
	public void sort(int[] array, int first, int end) {
		int pivot = 0;// 轴值记录所在位置
		if (first < end) {// 区间长度大于一才会执行一次划分,否则递归结束
			pivot = partition(array, first, end);// 进行一次划分
			sort(array, first, pivot - 1);// 递归地对左序列进行快速排序
			sort(array, pivot + 1, end);// 递归地对右序列进行快速排序
		}
	}

	/**
	 * 快速排序一次划分算法
	 * 
	 * @param array
	 *            待快速排序数组
	 * @param first
	 *            待快速排序序列的最左边所在位置
	 * @param end
	 *            待快速排序序列的最右边所在位置
	 * @return 每次划分序列轴值最后记录所在位置
	 */
	public int partition(int[] array, int first, int end) {

		while (first < end) {
			while (first < end && array[first] <= array[end]) {// 右侧扫描
				end--;
			}
			if (first < end) {
				swap(array, first, end);
				first++;
			}

			while (first < end && array[first] <= array[end]) {// 左侧扫描
				first++;
			}
			if (first < end) {
				swap(array, end, first);
				end--;
			}
		}
		return first;
	}

	/**
	 * 
	 * @param array
	 *            待交换数组
	 * @param i
	 *            待交换数组的一个索引
	 * @param j
	 *            待交换数组的另一个索引
	 */
	public void swap(int[] array, int i, int j) {
		int temp = array[i];
		array[i] = array[j];
		array[j] = temp;
	}
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值