算法练习集锦(一)

  • 贪心算法
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置
示例 1:
输入: [2,3,1,1,4]
输出: true
解释: 从位置 0 到 1 跳 1 步, 然后跳 3 步到达最后一个位置。
示例 2:
输入: [3,2,1,0,4]
输出: false
解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。

对于这一个题,我们根据题目要求能得出,只要能满足每次跳跃的距离大于等于数组的长度(而并不是一定得等于,测试数组中第一个值换成10也可以AC),就可以返回true,要是按照规则跳跃的最大长度不能超过数组的长度,那么就返回false.所以在题目中,我们要维护一个最大跳跃长度max,每次跳跃,跳跃到下一个点离起点的距离L和max进行比较,要是比max大,就将max值换为L,否则保持max值不变.只保留最大值,这就是贪心策略.

给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例:
输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
     从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
说明:
假设你总是可以到达数组的最后一个位置。

最小次数,看到这个我想应该能联想到求最短路径问题吧!对!请看下面源代码种终止循环条件就是只要满足最右端的长度和数组最后一个元素索引相同就跳出循环,这不正是广搜的思想吗?下面我们再分析跳跃计数过程的实现,算法要维护两个指针,l(左边界)和r(右边界),最远跳跃距离max_r,每次从左边界开始,向右边界跳跃,还是贪心策略记录能跳跃的最远距离max_r,直到i和右边界重合,将左边界移至之前的右边界的下一个地址,将右边界移至跳跃的最远的地址max_r,判断r只要和数组最大索引相等或比他大,结束!输出step,即为最少跳跃次数!每次是按照最大距离移动的.

以上两题的代码实现

//超级跳跃
//[2,3,1,1,4]
public class Test008 {
	
	//超级跳跃2   计算跳到终点的最小次数
	public static int CanOut1(int []a) {

		if(a.length == 1) return 0 ;
		int l = 0 ,r = 0 ,step =0;
	
		while( l<=r ) {
			
			int max_r = 0 ;
			for(int i = l;i <= r;i++) { 
				max_r = Math.max(max_r, i+a[i]);
			}
			l = r+1 ;
			r = max_r ;
			step++ ;
			if(r >= a.length-1)break ;
		}
		return step ;
	}
	//计算是否能跳到终点
	public static boolean CanOut(int [] a) {
		int maxs = 0 ;
		for(int i = 0 ; (i<a.length) && (i <= maxs) ;i++) {
			maxs = Math.max(maxs,a[i]+i) ;			
		}
		return maxs>=a.length-1 ;
	}
	public static void main(String[] args) {
		
		int a[] = {1,3,1,1,4};
		System.out.println(CanOut(a));
	}
}
  • 枚举排列
将abc的排列组合输出,不能存在重复序列.

这个算法是用递归实现.首先输出以a为首的序列,再输出以b为首的序列,然后输出以c为首的序列

import java.util.Scanner;
public class PaiLie {
	
	public static void swap(int i, int j, char[]c) {
		char temp = c[i] ;
		c[i] = c[j] ;
		c[j] = temp ;
	}
	
	public static void f(int k, char[]c) {
		
		if(k == c.length) {	
			System.out.println(c) ;
			return ;
		}
		
		for(int i = k; i < c.length ;i++) {
			
			//不和与自身相同元素进行交换,在递归后应该复原交换的值
			//进行下一次递归
			if((i != k && c[i]==c[k]) ) continue ;
			swap(i , k , c) ;
			f(k+1 , c) ;
			swap(i,k,c) ;
		}
	}
	public static void main(String[] args) {
		
		Scanner in = new Scanner(System.in);
		f(0 , in.nextLine().toCharArray()) ;
	}
}
A A 2 2 3 3 4 4 一共4种扑克牌,请把他们排成一行
 在两个A中间有一张扑克,量个2中间有两张,3中间有3张,4中间有4张

和上一题相似,我们只要能列出所有排列组合,然后加个条件判断,符合条件的字符串加入到集合中

import java.util.HashSet;
import java.util.Set;

public class Test009 {
	
	static char[]a = new char[] {'A','A','2','2','3','3','4','4'}; 
	
	static Set<String>set = new HashSet<String>();
	public static void swap(int i,int j,char []a) {
		char temp = a[i] ;
		a[i] = a[j] ;
		a[j] = temp ;
	}
	
	public static void f(int k , char[] a) {
		
		if(k==a.length) {
			String s = new String(a) ;
			//一个从最后一个元素开始找元素,找到便返回相应下标,另一个从第一个元素
			//找到并返回相应下标
			if(s.lastIndexOf('A')- s.indexOf('A') != 2)return ;
			if(s.lastIndexOf('2')- s.indexOf('2') != 3)return ;
			if(s.lastIndexOf('3')- s.indexOf('3') != 4)return ;
			if(s.lastIndexOf('4')- s.indexOf('4') != 5)return ;
			set.add(s) ;
			return ;
		}
		for(int i= k ;i<a.length ;i++) {
			if(i!=k&&a[i]==a[k])continue ;
			swap(i,k,a);
			f(k+1,a) ;
			swap(i,k,a);
		}
	}
	public static void main(String[] args) {
		
		f(0,a);
		for(String s : set) {
			System.out.println(s);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值