算法学习 贪心 堆应用 前缀树 N皇后

贪心算法

局部最优->全局最优
暴力解+对数器验证贪心策略

Q1:使若干字符串组成的字符串字典序最小

根据字符串字典序排序 再组合 ba,b显然错误

根据AB<BA的贪心策略排序,满足题意。(AB<BA)(BC<CB) ->(AC<CA)

Q2:切金条问题,长度为n的金条需要花费n金币,需要将长度为n的金条分成所需要的长度(a,b,c...)

哈夫曼树

Q3:会议问题,知道会议开始和结束的时间,如何使一天安排最多的会议。

根据结束时间最早排序

Q4:有M本金,可以完成k个项目(不可并行),知道项目的启动资金和收益,求最大收益。

两个堆,一个小顶堆(启动资金排序)用于存放启动不了的项目,一个大顶堆(收益排序)存放启动资金足够的项目,但大顶堆中无项目或者已完成K个项目停止。

堆的应用

Q1:随时取得数据流的中位数。

大致思路:用两个堆分别存放N/2的数,堆顶即为中位数

小顶堆存放大于中位数的数,大顶堆存放小于中位数的数。数据小于等于大顶堆时,属于中位数前,放大顶堆,大于时放小顶堆。当两堆的数据个数差大于2时,个数多的堆顶进个数小的堆。

 

前缀树

结点含pass,end值,结点数组分别表示多少以这个为前缀,多少个这个字符串,多少条往下的道路

创造和访问都直接按照字符串访问前缀树即可。

 

N皇后问题

朴素解法:

public static int num1(int n){
        if(n<1) return 0;
        //存放皇后位置 record[i]=j表示第i行的皇后放在j列
        int record[]=new int[n];
        return process1(0,record,n);
    }
    public static int process1(int i,int[] record,int n){
        //前0到 i-1行已经摆好,找i行应该放哪
        if(i==n) return 1; //0到i-1摆好则找到一种正确摆法
        int res=0;
        for(int j=0;j<n;j++){
            if(isValid(record,i,j)){
                record[i]=j;
                //此处是递归回溯的关键,过程类似树的遍历
                res+=process1(i+1,record,n);
            }
        }
        return res;
    }

    public static boolean isValid(int[] record,int i,int j){
        for(int k=0;k<i;k++){
            //同列或在斜线上
            if(record[k]==j||(Math.abs(i-j)==Math.abs(record[i]-j))){
                return false;
            }
        }
        return true;
    }


位运算优化:通过int类型的位数32位表示皇后所在的位置,只能实现32皇后之内,受限于数据位数。

public static int num1(int n){
        if(n<1 || n>32) return 0;
        //limit的后n位为1,表示可以摆放的位置
        int limit=n==32? -1:(1<<n)-1;
        return process1(limit,0,0,0);
    }
    public static int process1(int limit,int colLim,int leftLim,int rightLim){
        //limit表示全摆放完的状态,colLim、leftLim、rightLim标记不可摆放的位置。
        if(colLim==limit) return 1;
        int pos=limit&(~(colLim|leftLim|rightLim));
        //找到不受限的位置
        //limit  000 1 1 1 1 1 1 1 1
        //col    000 0 0 0 1 0 0 0 0
        //left   000 0 0 1 0 0 0 0 0
        //right  000 0 0 0 0 1 0 0 0
        //       000 0 0 1 1 1 0 0 0
        //       111 1 1 0 0 0 1 1 1
        //pos    000 1 1 0 0 0 1 1 1 此处1表示剩下5行可以摆放的位置
        int mostRightOne=0;
        int res=0;
        while(pos!=0){
            //mostRightOne表示选择的列
            mostRightOne=pos&(~pos+1);
            pos=pos-mostRightOne;
            res+=process1(limit,colLim|mostRightOne,
                    leftLim|mostRightOne<<1,
                    rightLim|mostRightOne>>>1);
            //>>>逻辑右移,高位补0
        }

        return res;
    }

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值