栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java算法题 之 暴力递归

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java算法题 之 暴力递归

java算法题 之 暴力递归
    • 暴力递归
      • N皇后(位运算)
      • 递归实现字符串求值
      • 字符串的全排列
      • 纸牌累计分数
      • 岛数量问题
      • 人气值
        • 错误代码
        • 平凡解限制
      • 返回字符串的所有子字符串(树形)
      • 数字转化成字母(树形)
      • 背包问题(树形)

暴力递归 N皇后(位运算)
class E {
    public static int num(int num) {
        if (num < 1 || num > 32) return 0;
        //limit用于限制在所有数据运算过程中保证除后num位的所有位数据均为零,来判断结束和标志结束
        int limit = num == 32 ? -1 : (1 << num) - 1;
        return process(limit, 0, 0, 0);
    }

    
    private static int process(int limit, int coLim, int leftLim, int rightLim) {
        if (limit == coLim) return 1;

        //(coLim | leftLim | rightLim)结果表示所有位上为1的位置均存在皇后,不能存放。
        //~后表示1的地方没有限制,可以存放皇后(但是,在32位的前32-num位上也为1,我们知道这是不合理的,因为不存在那么多的皇后)
        //limit&    表示将除num位的值变成0,这样就保证所有为1的元素均为空缺位置。
        int pos = limit & (~(coLim | leftLim | rightLim));
        int res = 0, mostRightOne;
        while (pos != 0) {//pos为0.说明不存在空缺位置
            mostRightOne = pos & (~pos + 1);//此时在后num位存在1,就将最右端的1取出。
            pos = pos - mostRightOne;//更新pos,将取出的1减掉,表明mostRightOne中1所对应的位存在了,不能放了。
            res += process(limit, coLim | mostRightOne  // 该mostRightOne位的皇后对于下一皇后纵向上的影响
                    , (leftLim | mostRightOne) << 1     // mostRightOne对于k=-1方向的影响
                    , (rightLim | mostRightOne) >> 1);  //mostRightOne对于k=1方向的影响
        }
        return res;
    }
}
递归实现字符串求值

public class Main {
	public static void main(String[] args) {
		int a = value("4-(1+2)*3+1");
		System.out.println(a);
	}

	private static int value(String string) {
		if (string == null || string.length() == 0) {
			return 0;
		}
		return value(string.toCharArray(), 0)[0];
	}

	private static int[] value(char[] str, int i) {
		linkedList list = new linkedList<>();
		int num = 0;
		int[] bra = null;
		while (i < str.length && str[i] != ')') {
			if (str[i] >= '0' && str[i] <= '9') {
				num = num * 10 + str[i++] - '0';
			} else if (str[i] != '(') {
				addNum(list, num);
				list.addLast(String.valueOf(str[i++]));
				num = 0;
			} else {
				bra = value(str, i + 1);
				num = bra[0];
				i = bra[1] + 1;
			}

		}
		addNum(list, num);
		return new int[] { getNum(list), i };
	}

	private static void addNum(linkedList list, int num) {
		if (!list.isEmpty()) {
			int cur = 0;
			String top = list.pollLast();
			if (top.equals("+") || top.equals("-")) {
				list.addLast(top);
			} else {
				cur = Integer.valueOf(list.pollLast());
				num = top.equals("*") ? (cur * num) : (cur / num);
			}
		}
		list.addLast(String.valueOf(num));

	}

	private static int getNum(linkedList list) {
		int res = 0;
		boolean add = true;
		String curString = null;
		int num = 0;
		while (!list.isEmpty()) {
			curString = list.pollFirst();
			if (curString.equals("+")) {
				add = true;
			} else if (curString.equals("-")) {
				add = false;
			} else {
				num = Integer.valueOf(curString);
				res += add ? num : (-num);
			}
		}
		return res;
	}
}
字符串的全排列

  • 我们通常都思路都是将所有字符依次放在最前面,例如ABC,第一位为A,B,C,然后判断第二位,那么我们如何在字符串中标记该字符已经被我们安排在前面了?
  • 若我们使用下标的方式,那么在每次选择都会产生一个下标,这样会很乱。
  • 于是我们可以通过将欲放在前面的字符就直接放在前面(将字符一次和后面的交换),用一个下标指引我们前面已经定了多少的元素。
  • 但是若我们交换后在后续调用时,数据顺序已经打乱,我们可能会造成重复情况,所以我们在每次运行后再将数据交换变成原来位置。
  • 但是当数据有重复字符时,会出现重复的全排列,这是我们就要判断交换的字符是否和之前交换的相同,若相同,就不用交换
class PB {
    public static List list=new ArrayList<>();
    public static void process(String string){
        char[] chars = string.toCharArray();
        process(chars,0);
    }
    private static void process(char[] chars, int i){
        if (i==chars.length){//结果
            list.add(new String(chars));
            return;
        }
        boolean[] isVisited=new boolean[26];//默认只有大写字母
        for (int j=i;j 
纸牌累计分数 

class PB {
    public static int win(int[] arr){
        if (arr.length==0)return 0;
        return Math.max(front(arr,0,arr.length-1), end(arr,0,arr.length-1));
    }
    //先手的人对应的数据
    private static int front(int[] arr,int left,int right){
        if (left==right)return arr[left];//先手的人,最后还剩一个数据就是这个人的
        //取那个值和下一次该我选的时候我的收益最大。
        return Math.max(arr[left]+end(arr,left+1,right),arr[right]+end(arr,left,right-1));
    }
    private static int end(int[] arr, int left, int right){
        if (left==right)return 0;
        return Math.min(front(arr,left+1,right),+front(arr,left,right-1));
    }
}
岛数量问题

class PB {
    private static int[][] arr;
    private static int N;
    private static int M;
    public static int process(int[][] arr){
        PB.arr=arr;
        PB.N=arr.length;
        PB.M=arr[0].length;
        int res=0;//记录结果
        for (int i=0;i=N||j<0||j>=M||arr[i][j]!=1)return;
        arr[i][j]=2;
        infect(i-1,j);
        infect(i+1,j);
        infect(i,j-1);
        infect(i,j+1);
    }
}
人气值

错误代码
public class Test {
    public static void process1(int start, int x, int y, int z, int end) {
        func(x, y, z, end, start);
    }
    private static int func(int x, int y, int z, int end, int thisNum) {
        if (end == thisNum) {
            return 0;
        }
        int resX = func(x, y, z, end, thisNum + 2) + x;
        int resY = func(x, y, z, end, thisNum * 2) + y;
        int resZ = func(x, y, z, end, thisNum - 2) + z;
        return Math.min(resX, Math.min(resY, resZ));
    }
}
平凡解限制
public class Test {
    public static void main(String[] args) {
        System.out.println(process1(3, 100, 1, 2, 6));

    }

    public static int process1(int x, int y, int z, int start, int end) {
        return func(x, y, z, end, start, 0, (end - start) / 2 * x);
    }

    
    private static int func(int x, int y, int z, int end, int thisNum, int coinsNum, int generalSolution) {
        if (end == thisNum) {
            return coinsNum;
        }
        if (coinsNum > generalSolution) {
            return Integer.MAX_VALUE;
        }
        int resX = func(x, y, z, end, thisNum + 2, coinsNum + x, generalSolution);
        int resY = func(x, y, z, end, thisNum * 2, coinsNum + y, generalSolution);
        int resZ = func(x, y, z, end, thisNum - 2, coinsNum + z, generalSolution);
        return Math.min(resX, Math.min(resY, resZ));
    }
}
返回字符串的所有子字符串(树形)
  • 将该问题看成二分类问题,将所有的单个字符元素是否存在看成一个事件,通过对所有的单个字符判读存在情况就可以得出所有子字符串
  • 这样可以理解为二叉树的情况,每一层的每个节点下有两个子节点,表示该层对应的字符是否添加进路径中,最后树的所有叶子节点对应的字符串就是所以子字符串
  • 我们采用动态生成树的递归方法对树进行动态的遍历。(该树必定为满树)
class PB {
    public static List list=new ArrayList<>();
    private static String s;
    public static void childrenString(String string){
        s=string;
        childrenString("",0);
    }
    
    private static void childrenString(String chlidString,int i){
        if (i==s.length()){//叶子节点
            list.add(chlidString);
            return;
        }
        childrenString(chlidString+s.charAt(i),i+1);//要这个字符
        childrenString(chlidString,i+1);//不要这个字符
    }
}
数字转化成字母(树形)

class PB {
    public static int process(String s,int i){
        //若一个不剩或这还剩一个,就返回1(保证剩的不为0),若此时不返回,说明还剩至少两个字符
        if (s.length()==i||(s.length()==i+1&&s.charAt(i)!='0'))return 1;
        if (s.charAt(i)=='0')return 0;//没有0开头匹配的元素
        int res=process(s,i+1);//一个字符的
        if (Integer.parseInt(s.substring(i,i+2))<=26)
            res+=process(s,i+2);//若满足匹配条件,进行两个字符的
        return res;//累加的结果返回就行了
    }
}
背包问题(树形)

  • 和返回字符串的所有子字符串相似,判断每个物品是否装进了袋子两种选择
  • 只需要用递归像树一样遍历所有选择取出最大值即可
  • 这样的题可以使用动态规划O(N²),递归O(2^N),关于递归转为动态规划,后续再说。
class PB {
    private static int maxBag;
    private static int[] weights;
    private static int[] values;
    public static int process(int[] weights,int[] values,int maxBag){
        PB.maxBag=maxBag;
        PB.weights=weights;
        PB.values=values;
        return process(0,0,0);
    }

    
    private static int process(int w,int v,int i){
        if (w>maxBag)return 0;
        if (i==weights.length)return v;
        return Math.max(process(w+weights[i],v+values[i],i+1),
                        process(w,v,i+1));
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/345407.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号