9.9递归和动态规划(六)——打印n对括号的所有有效组合(即左右括号正确配对)

/**

* 功能:打印n对括号的所有有效组合(即左右括号正确配对)。

*/

两种方法:

方法一:

	/**
	 * 思路:在括号的最前面或者原有的每对括号中面插入一对括号。

至于其它任何位置。比方字符串的末尾,都会跟之前的情况反复。
	 * 注意:将字符串放进结果列表之前。必须检查列表有无反复。
	 * @param remaining
	 * @return
	 */
	public static HashSet<String> generateParens(int remaining){
		HashSet<String> set=new HashSet<String>();

		if(remaining==0)
			set.add("");
		else{
			HashSet<String> prev=generateParens(remaining-1);
			for(String str:prev){
				//括号内插入
				for(int i=0;i<str.length();i++){
					if(str.charAt(i)=='('){
						String s=insertInside(str,i);
						set.add(s);//插入元素之前,HashSet会自己主动检查有无反复
					}
				}
				//括号最前面插入
				if(!set.contains("()"+str))
					set.add("()"+str);
			}
		}
		return set;
	}

	/**
	 * 在每对括号内插入
	 * @param str
	 * @param leftIndex
	 * @return
	 */
	public static String insertInside(String str,int leftIndex){
		String left=str.substring(0,leftIndex+1);//左括号之后插入括号,所以须要leftIndex+1
		String right=str.substring(leftIndex+1);
		return left+"()"+right;
	}

方法二:

	/**
	 * 思路:从头開始构造字符串,避免出现反复字符串。注意增加左括号和右括号,仅仅要字符串仍然有效。
	 * 每次递归调用,都有一个索引指向字符串的某个字符。选择左括号和右括号:
	 * 		1)左括号:仅仅要左括号还没实用完,就能够插入左括号。

* 		2)右括号:仅仅要不造成语法错误,就能够插入右括号(右括号比左括号多。即语法错误)。
	 * 因此。仅仅需记录同意插入的左右括号数目。假设还有左括号可用。就插入一个左括号。然后递归。
	 * 假设后括号比左括号多,(即使用中的左括号比右括号多)。就插入一个右括号,然后递归。

*
	 * 在字符串的每个索引相应位置插入左括号和右括号。并且绝对不会反复索引!!!
	 * @param count
	 * @return
	 */
	public static ArrayList<String> generateParens2(int count){
		ArrayList<String> list=new ArrayList<String>();
		char[] str=new char[count*2];
		addParens(list,count,count,str,0);

		return list;
	}

	public static void addParens(ArrayList<String> list, int leftRem, int rightRem, char[] str, int count) {
		// TODO Auto-generated method stub
		if(leftRem<0||rightRem<leftRem)
			return;

		if(leftRem==0&&rightRem==0){
			String s=String.copyValueOf(str);
			list.add(s);
		}

		if(leftRem>0){
			str[count]='(';
			addParens(list, leftRem-1, rightRem, str, count+1);
		}

		if(rightRem>leftRem){
			str[count]=')';
			addParens(list, leftRem, rightRem-1, str, count+1);

		}
	}
时间: 2024-11-08 21:01:44

9.9递归和动态规划(六)——打印n对括号的所有有效组合(即左右括号正确配对)的相关文章

实现一种算法,打印n对括号的全部有效组合(即左右括号正确配对)

public static Set<String> generateParens(int remaining) { Set<String> set=new HashSet<String>(); if(remaining == 0) set.add(""); else { Set<String> prev=generateParens(remaining-1); for(String str:prev) { for(int i=0;i<

9.9递归和动态规划(六)——打印n对括号的全部有效组合(即左右括号正确配对)

/** * 功能:打印n对括号的全部有效组合(即左右括号正确配对). */ 两种方法: 方法一: /** * 思路:在括号的最前面或者原有的每对括号里面插入一对括号.至于其他任意位置,比如字符串的末尾,都会跟之前的情况重复. * 注意:将字符串放进结果列表之前,必须检查列表有无重复. * @param remaining * @return */ public static HashSet<String> generateParens(int remaining){ HashSet<St

左神算法第八节课:介绍递归和动态规划(汉诺塔问题;打印字符串的全部子序列含空;打印字符串的全排列,无重复排列;母牛数量;递归栈;数组的最小路径和;数组累加和问题,一定条件下最大值问题(01背包))

暴力递归: 1,把问题转化为规模缩小了的同类问题的子问题 2,有明确的不需要继续进行递归的条件(base case) 3,有当得到了子问题的结果之后的决策过程 4,不记录每一个子问题的解 动态规划 1,从暴力递归中来 2,将每一个子问题的解记录下来,避免重复计算 3,把暴力递归的过程,抽象成了状态表达 4,并且存在化简状态表达,使其更加简洁的可能 一:递归 1. 汉诺塔问题 汉诺塔问题(不能大压小,只能小压大),打印n层汉诺塔从最左边移动到最右边的全部过程. 左中右另称为 from.to.hel

算法初级面试题08——递归和动态规划的精髓、阶乘、汉诺塔、子序列和全排列、母牛问题、逆序栈、最小的路径和、数组累加成指定整数、背包问题

第八课主要介绍递归和动态规划 介绍递归和动态规划 暴力递归: 1,把问题转化为规模缩小了的同类问题的子问题 2,有明确的不需要继续进行递归的条件(base case) 3,有当得到了子问题的结果之后的决策过程 4,不记录每一个子问题的解 动态规划 1,从暴力递归中来 2,将每一个子问题的解记录下来,避免重复计算 3,把暴力递归的过程,抽象成了状态表达 4,并且存在化简状态表达,使其更加简洁的可能 图灵引入的是:我不知道怎么算,但是我知道怎么试.知道怎么暴力破解出来. 要学会,练习懂得怎么尝试.

利用递归和动态规划来求解组合数

组合数定义:从m个不同元素中,任取n(n≤m)个元素并成一组,叫做从m个不同元素中取出n个元素的一个组合:从m个不同元素中取出n(n≤m)个元素的所有组合的个数,叫做从m个不同元素中取出n个元素的组合数. 下面是一种比较通俗的计算公式: 其递归公式为: c(n,m)=c(n-1,m-1)+c(n-1,m) 下面是c++实现该递归算法: #include <iostream> #include <stdlib.h> #define EXIT -1 using namespace st

70. Climbing Stairs【leetcode】递归,动态规划,java,算法

You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? Note: Given n will be a positive integer. 题目分析:每次只能走1或2步,问n步的话有多少中走法???? 可以用动态规划和递归解

斐波那契数列的实现(简单递归和动态规划)

斐波那契数列的实现(简单递归和动态规划) 一.简单递归的实现 1 #include "stdafx.h" 2 #include <string> 3 using namespace std; 4 int f(int n) 5 { 6 if (n == 0) 7 { 8 return 0; 9 } 10 if (n == 1) 11 { 12 return 1; 13 } 14 return f(n - 1) + f(n - 2); 15 } 16 int _tmain(in

用递归正/逆序打印一个数组,以及调用返回的过程理解

1 #include <stdio.h> 2 /* 3 题目:用递归正/逆序打印数组的元素,以及递归调用的过程理解 4 正序打印数组解题思路:第一:数组元素是连续的.知道第一个元素的地址,就能推算出第二个元素的地址.以此类推 5 第二:数组的结束条件:i = sizeof(arr)/4 -1; 此时的值为arr[sizeof(arr)/4-1]; 6 第三:后一个元素的值的下标 = 前一个元素的值的下标+1 (通项公式) 7 */ 8 void arr1(int *p,int n,int *p

【动态规划专题】1:斐波拉契数列问题的递归和动态规划

<程序员代码面试指南--IT名企算法与数据结构题目最优解> 左程云 著 斐波拉契数列问题的递归和动态规划 [题目]:给定整数N,返回斐波拉契数列的第N项.补充问题1:给定整数N,代表台阶数,一次可以跨2个或者1个台阶,返回有多少种走法.补充问题2:假设农场中成熟的母牛每年只会生产1头小母牛,并且永远不会死.第一年农场只有1只成熟的母牛,从第2年开始,母牛开始生产小母牛.每只小母牛3年后成熟又可以生产小母牛.给定整数N,求出N年后牛的数量. [举例]斐波拉契数列f(0)=0, f(1)=1,f(