Java科普之算法剖析

简介: 本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处!       从小白晋升,一路走来;从helloworld,到JFrame,再到Android;从城外小子,到内城的阶...


本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处!


       从小白晋升,一路走来;从helloworld,到JFrame,再到Android;从城外小子,到内城的阶梯,站在高耸入云的阶梯上向前望;从迷茫的时代,到苦逼的时代,再到自信的时代;这些路有些艰难,有些坎坷,但--还算顺利;有过困惑,有过烦恼,有过委屈,但一路向前,风雨无阻;前言是遥远的,前方是未知的,前方是广阔的,前方是美好的;我要呼吁广大IT同胞们,让我们向着更遥远、更广阔、更美好的充满未知的未来出发吧!去贪婪的吮吸每一滴“蜜露”,用知识的精髓武装自己,斗志昂扬一如既往的用兴趣开路,去探寻属于自己的一片天地!


       今天冒昧给大家讲讲算法的故事。


       在从简单的逻辑写起,从完成一个控件、多个控件,走了一条线程、一条进程;到完成一个模块、若干模块,实现界面之间的交互、控件自定义;再到缓存、数据库、网络交互,内存管理、系统调优、架构扩展;最后又回归逻辑、研究算法,研究层与层之间的调用、依赖,抽象、继承、接口、反射等一些基础的概念;简而言之,把最简单的东西做到极致,那牛逼了!


       百度解释:算法复杂度分为时间复杂度和空间复杂度。其作用: 时间复杂度是指执行算法所需要的计算工作量;而空间复杂度是指执行这个算法所需要的内存空间。(算法的复杂性体现在运行该算法时的计算机所需资源的多少上,计算机资源最重要的是时间和空间(即寄存器)资源,因此复杂度分为时间和空间复杂度。)
       接下来依次讲几个算法,冒泡、选择……

       冒泡算法原理:两个两个的比较,其中较大的与较小的换位,每次都能排出剩下数中的最大数,放剩下数的最后;最终排出整齐的数列。 

        时间复杂度:倒序最大,Cmax=n*(n-1)/2,为T(n^2);正序最小,Cmin=n,为T(n);按实际情况来算。

        空间复杂度为:最坏情况,每两个就要换一回,则为n/2+(n-1)/2+……+2/2=n(n+1)/4,Omax=O(n^2);最好情况,已排好,则为O(0)。

        代码如下:

public void testBubbleSort() {

		int[] sortArray = { 4, 7, 9, 3, 6, 8,11 };
		for (int i = 0; i < sortArray.length-1 ; i++) {
			boolean isSort = false;
			for (int j = 0; j < sortArray.length -1-i; j++) {
				if (sortArray[j] > sortArray[j + 1]) {
					int temp = sortArray[j];
					sortArray[j] = sortArray[j + 1];
					sortArray[j + 1] = temp;
					isSort = true;
				}
			}
			if (!isSort)
				break;
		}
		System.out.println(Arrays.toString(sortArray));
	}

        选择排序原理:第一次,首个与后面的进行比较,把最小的放首位;第二次,次个与后面的进行比较,把次小的放次位;依次进行。

        与冒泡的区别在于:选择排序找出最小的下标,然后与此次开始位置数字置换,冒泡需要两个两个的换位置;从这个意义上来说,选择排序占用内存更少,拥有更小的空间复杂度。

        时间复杂度:最坏情况,n(n+1)/2,为Tmax=T(n^2);最好情况,已排好,则为T(n)。

        空间复杂度;最坏情况为O(n),最好为O(0),分别为正好相反或已排好。

        代码如下:

public void testChooseSort() {

		int min;
		for (int i = 0; i < sortArray.length - 1; i++) {
			min = i;
			for (int j = i + 1; j < sortArray.length - 1 - i; j++) {
				if (sortArray[min] > sortArray[j]) {
					min = j;
				}
			}
			if(min!=i){
				int temp=sortArray[min];
				sortArray[min]=sortArray[i];
				sortArray[i]=temp;
			}
		}
		System.out.println(Arrays.toString(sortArray));
	}

快速排序:从第2个开始,如果第2个比第1个大,则两者交换;第3个,放在前2个已经排序的队列中,合适的位置;第4个放在前3个已经排序的队列中,合适的位置;继续,最终直接排出有顺序的队列。


构建队列,计算二叉树叶子值的和

	static class TreeNode {
		int val;
		TreeNode left;
		TreeNode right;

		public TreeNode(int val) {
			this.val = val;
		}
	}

	/**
	 * 1 2 3 4 5 6 7
	 * 
	 * @param root
	 * @return
	 */
	public static void buildTree(TreeNode root) {
		if (root.val >= 4) {
			return;
		}
		TreeNode left = new TreeNode(root.val + 1);
		TreeNode right = new TreeNode(root.val + 2);
		root.left = left;
		root.right = right;
		buildTree(root.left);
		buildTree(root.right);
	}

	public static void main(String[] args) {
		TreeNode root = new TreeNode(1);
		buildTree(root);
		int sum = 0;
		System.out.println(sumTree(root, sum));
	}

	public static int sumTree(TreeNode root, int sum) {
		if (root == null)
			return sum;
		sum += root.val;
		sum = sumTree(root.left, sum);
		sum = sumTree(root.right, sum);
		return sum;
	}

贪心算法:

1、给分数不同的小朋友分糖果

2、旁边分数高的要比分数低的分的多

3、求最少糖果数

	public static int candy(int[] ratings) {
		if (ratings == null || ratings.length == 0)
			return 0;
		int[] candies = new int[ratings.length];
		for (int i = 0, size = ratings.length; i < size; i++) {
			if (i == 0) {
				candies[i] = 1;
				continue;
			}
			if (ratings[i] > ratings[i - 1]) {
				candies[i] = candies[i - 1] + 1;
			} else {
				candies[i] = 1;
			}
		}
		int sum = candies[ratings.length - 1];
		for (int i = ratings.length - 2; i >= 0; i--) {
			if (ratings[i] > ratings[i + 1]) {
				candies[i] = Math.max(candies[i], candies[i + 1] + 1);
			}
			sum += candies[i];
		}
		return sum;
	}

	public static void main(String[] args) {
		int[] candy = new int[] { 4, 2, 3, 4, 1 };
		System.out.println(candy(candy));
	}


拓展学习:Java科普之加密算法

其他有趣的算法:


如赛马问题,25匹马,5个赛道,如何在不用工具的情况下,找到最快的5匹。问题可以简化为3匹马,3个赛道。
分A B C三组马,各赛一场,结果如下:
A1 A2 A3
B1 B2 B3
C1 C2 C3
3场第1名赛一场,得出第1名
如果是A1,则A2跟B1和C1比1场,其他同理,找出第2名
如果是B1,则A2跟B2和C1比1场,其他同理,找出第3名
比赛结束,共需要6场
同理可算出,25匹马需要10场。


如运煤问题,3000吨煤,用载重1000吨的火车,从原点运往终点,路程1000公里,每公里消耗1吨煤,到终点时煤剩几何?
粗略一算,第一种方案:
第一轮,
第1次,先拉1000吨到A,卸下500吨,返回,行程250公里
第2次,再拉1000吨到A,卸下500吨,返回,行程250公里,同理第三次
第3次后,A地剩下1500吨煤,行程250公里
第二轮
继续第4次,同上,到B地行程187.5公里,每次卸下375吨货物
两轮后,行程437.5公里,剩下货物750吨
第三轮
一次性运到,共剩余312.5吨
分析:由于第三轮每次只运750吨,运量未满,导致最终运送较少。
粗略一算,第二种方案:
第1次,先拉1000吨到A, 卸下500吨 行程250公里 ,返回
第2次,再拉1000吨到A,加上250吨满载, 剩下250吨;走250公里到B, 卸下250吨,总行程250公里,返回
第3次,再拉1000吨到A,加上250吨满载;再走250公里到B,加上前两次剩下的共500吨,满载1000吨继续
直行到终点,共剩余 500吨
分析:似乎比较完美,每次都是满载。
粗略一算,第三种方案:
变下思路,将此题变成n千吨煤,可以走多少公里,即消耗多少
那么1000吨走1000公里,2000吨由于中间要折回+第1次向前走共3次即1000*(1+1/3)公里,同理可得3000吨走
1000*(1+1/3+1/5)公里,n千吨可走1000*(1+1/3+1/5+……+1/(2n-1))公里
那么3000公里剩余多少呢?前两句已经讲了3000吨可走的公里,每公里1吨,多出多少公里即多出多少吨
即1000*(1+1/3+1/5)-1000=1600/3吨,即 533.33吨。功夫不负有心人,这就是最终答案!


再如 扔鸡蛋问题,100层楼,2个蛋,n层楼以下扔下不碎,以上碎,问要扔几次才能确认
则声明有x次机会,则最多可能尝试的总楼层数为,x+(x-1)+(x-2)+……+1=x*(x-1)/2
如果100层,则判断小于100即可,结果呢为为14,即 至少要扔14次(则从14层开始扔)


目录
相关文章
|
2天前
|
算法 安全 Java
性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
【4月更文挑战第28天】性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
32 1
性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
|
2天前
|
搜索推荐 算法 Java
滚雪球学Java(29):数组长度和排序算法:让你的程序更高效
【5月更文挑战第4天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
11 0
滚雪球学Java(29):数组长度和排序算法:让你的程序更高效
|
2天前
|
设计模式 算法 Java
[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式
[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式
|
2天前
|
搜索推荐 算法 Java
Java实现的常用八种排序算法
提到数据结构与算法,无法避免的一点就包含排序,熟练的掌握各种排序算法则是一个程序员必备的素质之一,除此之外,排序算法也是当下各大技术公司比较喜欢问的技术点,所以,就这一点JavaBuild整理了常见的8种排序算法
12 0
|
2天前
|
机器学习/深度学习 数据采集 算法
使用 Java 实现机器学习算法
【4月更文挑战第19天】Java在数据驱动时代为机器学习提供支持,具备丰富的数学和数据结构库,适用于实现线性回归、决策树、SVM和随机森林等算法。实现时注意数据预处理、模型选择、评估指标和可视化。利用Java的库和编程能力可构建高效模型,但需按问题需求选择合适技术和优化方法。
|
2天前
|
算法 安全 Java
java代码 实现AES_CMAC 算法测试
该代码实现了一个AES-CMAC算法的简单测试,使用Bouncy Castle作为安全提供者。静态变量K定义了固定密钥。`Aes_Cmac`函数接受密钥和消息,返回AES-CMAC生成的MAC值。在`main`方法中,程序对给定的消息进行AES-CMAC加密,然后模拟接收ECU的加密结果并进行比较。如果两者匹配,输出&quot;验证成功&quot;,否则输出&quot;验证失败&quot;。辅助方法包括将字节转为16进制字符串和将16进制字符串转为字节。
|
2天前
|
搜索推荐 Java
Java排序算法
Java排序算法
20 0
|
2天前
|
搜索推荐 Java
Java基础(快速排序算法)
Java基础(快速排序算法)
25 4
|
2天前
|
搜索推荐 算法 Java
Java基础(冒泡排序算法)
Java基础(冒泡排序算法)
19 3
|
2天前
|
存储 缓存 监控
深入理解Java线程池ThreadPoolExcutor实现原理、数据结构和算法(源码解析)
Java线程池的核心组件包括核心线程数、最大线程数、队列容量、拒绝策略等。核心线程数是线程池长期维持的线程数量,即使这些线程处于空闲状态也不会被销毁;最大线程数则是线程池允许的最大线程数量,当任务队列已满且当前线程数未达到最大线程数时,线程池会创建新线程执行任务;队列容量决定了任务队列的最大长度,当新任务到来时,如果当前线程数已达到核心线程数且队列未满,任务将被放入队列等待执行;拒绝策略则定义了当线程池无法处理新任务时的行为,如抛出异常、丢弃任务等。
56 1