贪心算法

87 阅读2分钟

image.png

public static  Info process(Node x) {
    if (x == null) {
        return new Info(true, true, 0);
    }
    Info leftInfo = process(x.left);
    Info rightInfo = process(x.right);
    int height = Math.max(leftInfo.height, rightInfo.height) + 1;
    boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;
    boolean isCBT = false;
    if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height) {
        isCBT = true;
    } else if (leftInfo.isCBT && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
        isCBT = true;
    } else if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
        isCBT = true;
    } else if (leftInfo.isFull && rightInfo.isCBT && leftInfo.height == rightInfo.height) {
        isCBT = true;
    }
    return new Info(isFull, isCBT, height);
}

2.返回a和b的最低公共祖先

给定一棵二叉树的头节点head,和另外两个节点a和b。返回a和b的最低公共祖先

最低公共祖先:节点的最近汇聚的公共祖先

image.png

//最低公共节点
public static Node lowestAncestor2(Node head, Node a, Node b) {
    
}
​
public static class Info {
    public boolean findA;
    public boolean findB;
    public Node ans;
    
    public Info (boolean fA, boolean fB, Node an) {
        findA = fA;
        findB = fB;
        ans = an;
    }
}
​
public static Info process(Node x, Node a, Node b) {
    if (x == null) {
       return new Info(false, false, null);
    }
    
    Info leftInfo = process(x.left, a, b);
    Info rightInfo = process(x.right, a, b);
    boolean findA = (x == a) || leftInfo.findA || rightInfo.findA;
    boolean findB = (x == b) || leftInfo.findB || rightInfo.findB;
    Node ans = null;
    if (leftInfo.ans != null) {
        ans = leftInfo.ans;
    } else if (rightInfo.ans != null) {
        ans = rightInfo.ans;
    } else {
        if (findA && findB) {
            ans = x;
        }
    }
    return new Info(findA, findB, ans);
}
​

派对的最大快乐值

public static class Employee {
    public int happy;
    public List<Employee> nexts;
​
    public Employee(int h) {
        happy = h;
        nexts = new ArrayList<>();
    }
}
​
public static int maxHappy2(Employee head) {
    Info allInfo = process(head);
    return Math.max(allInfo.no, allInfo.yes);
}
​
public static class Info {
    public int no;
    public int yes;
​
    public Info(int n, int y) {
        no = n;
        yes = y;
    }
}
​
public static Info process(Employee x) {
    if (x == null) {
        return new Info(0,0);
    }
    int no = 0;
    int yes = x.happy;
    for (Employee next: x.nexts) {
        Info nextInfo = process(next);
        no += Math.max(nextInfo.no, nextInfo.yes);
        yes += nextInfo.no;
    }
    return new Info(no, yes);
}

贪心算法

1)最自然智慧的算法

2)用一种局部最功利的标准,总是做出在当前看来是最好的选择

3)难点在于证明局部最功利的标准可以得到全局最优解

4)对于贪心算法的学习主要以增加阅历和经验为主

给定一个由字符串组成的数组strs,必须把所有的字符串拼接起来,返回所有可能的拼接结果中,字典序最小的结果

image.png

(1)使用的是贪心加暴力的递归,这里我们可以添加比较器的方法,一个个的将每个字符的次序比较,得到最终的最合适的结果

public static class MyComparator implements Comparator<String> {
    @Override
    public int compare(String a, String b) {
        return (a + b).compareTo(b + a);
    }
}
​
public static String lowestString2(String[] strs) {
    if (strs == null || strs.length == 0) {
        return "";
    }
    Arrays.sort(strs, new MyComparator());
    Strng res = "";
    for (int i = 0; i < strs.length; i++) {
        res += strs[i];
    }
    return res;
}

image.png

(2)暴力的递归

public static String lowestString1(String[] strs) {
    if (strs == null || strs.length == 0) {
        return "";
    }
    TreeSet<String> ans = process(strs);
    return ans.size() == 0 ? "" : ans.first();
}
​
//strs 中所有的字符串全排列,返回所有的可能结果
public static TreeSet<String> process(String[] strs) {
    TreeSet<String> ans = new TreeSet<>();
    if (strs.length == 0) {
        ans.add("");
        return ans;
    }
    for (int i = 0; i < strs.length; i++) {
        String first = strs[i];
        String[] nexts = removeIndexString(strs, i);
        reeSet<String> next = process(nexts);
        for (String cur: next) {
            ans.add(first + cur);
        }
    }
    return ans;
​
    public static String[] removeIndexString(String[] arr, int index) {
        int N = arr.length;
        String[] ans = new String[N-1];
        int ansIndex = 0;
        for (int i = 0; i<N; i++) {
            if (i != index) {
                ans[ansIndex++] = arr[i];
            }
        }
        return ans;
    }
​

一些项目要占用一个会议室宣讲,会议室不能同时容纳两个项目的宣讲。给你每一个项目开始的时间和结束的时间你来安排宣讲的日程,要求会议室进行的宣讲的场次最多。返回最多的宣讲场次。

//会议开始时间和结束时间,都是数值,不会《0
public static int bestArrange2(Program[] programs) {
    Arrays.sort(programs, new ProgramComparator());
    int timeLine = 0;
    int res = 0;
    //遍历每一个会议,结束时间早的会议先遍历
    for (int i=0; i < programs.length; i++) {
        if (timeLine <= programs[i].start) {
            res ++;
            timeLine = programs[i].end;
        }
    }
    return res;
}
​
public static class ProgramComparator implements Comparator <Program> {
    @Override
    public int compare(Program o1, Program o2) {
        return o1.end - o2.end;
    }
}
public static int bestArrange1(Program[] programs) {
    if (programs == null || programs.length == 0) {
        return 0;
    }
    return process(programs, 0, 0);
}
// 还剩下的会议都放在programs里
// done之前已经安排了多少会议的数量
// timeLine目前来到的时间点是什么
​
// 目前来到timeLine的时间点,已经安排了done多的会议,剩下的会议programs可以自由安排
// 返回能安排的最多会议数量
public static int process(Program[] programs, int done, int timeLine) {
    if (programs.length == 0) {
        return done;
    }
    //还剩下会议
    int max = done;
    //当前安排的会议是什么会,每一个都枚举
    for (int i = 0; i < programs.length; i++) {
        if (programs[i].start >= timeLine) {
            Program[] next = copyButExcept(programs, i);
            max = Math.max(max, process(next, done + 1, programs[i].end));
        }
    }
    return max;
}
​
public static Program[] copyButExcept(Program[] programs, int i) {
    Program[] ans = new Program[programs.length - 1];
    int index = 0;
    for (int k = 0; k < programs.length; k++) {
        if (k != i) {
            ans[index++] = programs[k];
        }
    }
    return ans;
}

分金问题---一块金条切成两半,是需要花费和长度数值一样的铜板的。

比如长度为20的金条,不管怎么切,都要花费20个铜板。 一群人想整分整块金条,怎么分最省铜板?

public static int lessMoney2(int[] arr) {
    PriorityQueue<Integer> pQ = new PriorityQueue<>();
    for (int i = 0; i < arr.length; i++) {
        pQ.add(arr[i]);
    }
    int sum = 0;
    int cur = 0;
    while (pQ.size() > 1) {
        cur = pQ.poll() + pQ.poll();
        sum += cur;
        pQ.add(cur);
    }
    return sum;
}

输入: 正数数组costs、正数数组profits、正数K、正数M

image.png

//最多k个项目
//W是初始资金
// Profits[] Capital[] 一定等长
//返回最终最大的资金
public static int findMaximizedCapital(int k, int w, int[] Profits, int[] Capital) {
    PriorityQueue<Program> minCostQ = new PriorityQueue<>(new MinCostComparator());
    PriorityQueue<Program> maxProfitQ = new PriorityQueue<>(new MaxProfitComparator());
    for (int i=0; i<Profits.length; i++) {
        minCostQ.add(new Program(Profits[i], Capital[i]));
    }
    for (int i=0; i<k; i++) {
        while (!minCostQ.iaEmpty() && minCostQ.peek().c < k) {
            maxProfitQ.add(minCostQ.poll());
        }
        if (maxProfitQ.isEmpty()) {
            return W;
        }
        W += maxProfitQ.poll().p;
    }
    return W;
}

public static class Program {
    public int p;
    public int c;

    public Program(int p, int c) {
        this.p = p;
        this.c = c;
    }
}

public static class MinCostComparator implements Comparator<Program> {

    @Override
    public int compare(Program o1, Program o2) {
        return o1.c - o2.c;
    }
}

public static class MaxProfitComparator implements Comparator<Program> {

    @Override
    public int compare(Program o1, Program o2) {
        return o2.p - o1.p;
    }
}

\