左神算法之中级提升班(9)

【案例1】

【题目描述】

左神算法之中级提升班(9)_第1张图片

 【思路解析】

因为它数字的范围只能为1 - n,然后数组范围0 - n-1,所以说如果没有缺失值的话,每个i位置应该放i + 1,所以我们直接对每个数组完成这个操作,让每个i位置尽可能放i+1,如果有些位置不是i+1,则这些位置就是缺失值,遍历打印即可 。

【代码实现】

/**
 * @ProjectName: study3
 * @FileName: Ex1
 * @author:HWJ
 * @Data: 2023/7/31 9:48
 */
public class Ex1 {
    public static void main(String[] args) {
        int[] arr = {1, 3, 4, 3};
        printNumberNoInArray(arr);
    }

    public static void printNumberNoInArray(int[] arr){
        if (arr == null || arr.length == 0){
            return;
        }
        for (int i : arr) {
            modify(i, arr);
        }
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] != i + 1){
                System.out.println(i + 1);
            }
        }

    }

    // 这里实现让每个i位置上尽可能方i+1
    public static void modify(int value, int[] arr){
        while(arr[value - 1] != value){
            int tmp = arr[value - 1];
            arr[value - 1] = value;
            value = tmp;
        }
    }

}

【案例2】

【题目描述】

左神算法之中级提升班(9)_第2张图片

【思路解析  平凡解技巧  从业务中分析终止条件 重点

这道题容易想到使用暴力递归来解决,但限制条件只有一个cur == end,不足以作为basecase,需要补充限制条件,因为end和start均为偶数,且end > > start ,所以有一个只用点赞到达end的平凡解,如果高于这个花费的解,直接不考虑。

从业务中分析,因为他有一个私聊是可以-2,然后在递归中,它有一个分支可能一直在-2,导致无法到达end,所以限制条件增加一个为start已经小于0停止。

从业务中分析,他有一个*2的方式,但是总有一次*2可以使他第一次比b大,此时如果再次*2就会花费更多的私聊钱,再分析再次*2会大于2*b,所以增加一个限制条件start不能大于 2 * b;

【代码实现】

/**
 * @ProjectName: study3
 * @FileName: Ex2
 * @author:HWJ
 * @Data: 2023/7/31 10:39
 */
public class Ex2 {
    public static void main(String[] args) {
        System.out.println(getMinMoney(3, 100, 1, 2, 6));
    }

    public static int getMinMoney(int x, int y, int z, int start, int end) {
        int limitCoin = ((end - start) / 2) * x;
        int limitAim = end * 2;
        return process(x, y, z, start, end, 0, limitCoin, limitAim);
    }

    // preMoney代表当前已经花了多少钱
    // limitCoin代表平凡解所需要花费的钱币
    // limitAim 代表当前start的上界
    public static int process(int x, int y, int z, int start, int end, int preMoney, int limitCoin, int limitAim) {
        if (start == end) {
            return preMoney;
        }
        if (start < 0) {
            return Integer.MAX_VALUE;
        }
        if (preMoney > limitCoin) {
            return Integer.MAX_VALUE;
        }
        if (start > limitAim) {
            return Integer.MAX_VALUE;
        }
        int p1 = process(x, y, z, start + 2, end, preMoney + x, limitCoin, limitAim);
        int p2 = process(x, y, z, start * 2, end, preMoney + y, limitCoin, limitAim);
        int p3 = process(x, y, z, start - 2, end, preMoney + z, limitCoin, limitAim);
        return Math.min(p1, Math.min(p2, p3));
    }

}

【案例3】

【题目描述】

左神算法之中级提升班(9)_第3张图片

左神算法之中级提升班(9)_第4张图片

【思路解析】

可以通过后面关联矩阵生成一个图,然后从末尾H开始做一个图的宽度优先遍历,每个节点实现一个哈希表,然后哈希表里面维护当花费天数增加时,收益一定增加,然后每个节点就得到了它独自的哈希表,然后最后将所有哈希表汇总,这样就得到了所有完成方式。然后最后根据限制天数来查表即可。最后这里也可以用大根堆来做,只有小于限制天数的值才加入,然后里面根据收益大小来维护大根堆。两个方式都差不多。

【案例4】

【题目描述】

左神算法之中级提升班(9)_第5张图片

 【思路解析】

因为& | ^ 这几个运算都是二元运算,则表达式长度应该为奇数且大于1,满足奇数位上只有0或1,偶数位上只有&、|或^运算符,如果不满足此规则的字符串直接返回0.

然后对于组合就有如下定义,对于每一个确定的表达式组合应有确定的括号,对于不同的括号填充,则认为不同的组合方式。括号可以认为是进行运算时的顺序规定,不一定真的要在字符串上填充括号。

【代码实现】

import java.util.Scanner;

/**
 * @ProjectName: study3
 * @FileName: Ex4
 * @author:HWJ
 * @Data: 2023/9/11 14:21
 */
public class Ex4 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String str = input.next();
        boolean desire = input.nextBoolean();
        if (!check(str)){
            System.out.println(0);
        }else {
            char[] charArray = str.toCharArray();
            int ans = count(charArray, 0, charArray.length  - 1, desire);
            System.out.println(ans);
        }
    }

    public static boolean check(String str){
        // 因为 | & ^ 运算都是二元运算,所以有效字符串长度应该为奇数,并且奇数位是 1 或者 0, 偶数位是 二元运算符
        if (str.length() % 2 == 0 || str.length() == 1){
            return false;
        }
        char[] charArray = str.toCharArray();
        for (int i = 0; i < charArray.length; i+=2) {
            if (charArray[i] != '0' && charArray[i] != '1'){
                return false;
            }
        }
        for (int i = 1; i < charArray.length; i+=2) {
            if (charArray[i] != '|' && charArray[i] != '&' && charArray[i] != '^'){
                return false;
            }
        }
        return true;
    }

    public static int count(char[] chars, int L, int R, boolean desire) {
        if (L == R) {
            if (chars[L] == '0') {
                return desire ? 0 : 1;
            } else {
                return desire ? 1 : 0;
            }
        }
        int res = 0;
        for (int i = L + 1; i < R; i += 2) {
            if (desire) {
                switch (chars[i]) {
                    case '&':
                        res += count(chars, L, i - 1, true) * count(chars, i + 1, R, true);
                        break;
                    case '|':
                        res += count(chars, L, i - 1, true) * count(chars, i + 1, R, true);
                        res += count(chars, L, i - 1, true) * count(chars, i + 1, R, false);
                        res += count(chars, L, i - 1, false) * count(chars, i + 1, R, true);
                        break;
                    case '^':
                        res += count(chars, L, i - 1, true) * count(chars, i + 1, R, false);
                        res += count(chars, L, i - 1, false) * count(chars, i + 1, R, true);
                        break;
                }
            } else {
                switch (chars[i]) {
                    case '|':
                        res += count(chars, L, i - 1, false) * count(chars, i + 1, R, false);
                        break;
                    case '&':
                        res += count(chars, L, i - 1, false) * count(chars, i + 1, R, false);
                        res += count(chars, L, i - 1, true) * count(chars, i + 1, R, false);
                        res += count(chars, L, i - 1, false) * count(chars, i + 1, R, true);
                        break;
                    case '^':
                        res += count(chars, L, i - 1, true) * count(chars, i + 1, R, true);
                        res += count(chars, L, i - 1, false) * count(chars, i + 1, R, false);
                        break;
                }
            }
        }
        return res;
    }
}

【动态规划代码】

import java.util.Scanner;

/**
 * @ProjectName: study3
 * @FileName: Ex4_2
 * @author:HWJ
 * @Data: 2023/9/11 15:10
 */
public class Ex4_2 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String str = input.next();
        boolean desire = input.nextBoolean();
        int ans = dp(str, desire);
        System.out.println(ans);
    }

    public static boolean check(String str) {
        // 因为 | & ^ 运算都是二元运算,所以有效字符串长度应该为奇数,并且奇数位是 1 或者 0, 偶数位是 二元运算符
        if (str.length() % 2 == 0 || str.length() == 1) {
            return false;
        }
        char[] charArray = str.toCharArray();
        for (int i = 0; i < charArray.length; i += 2) {
            if (charArray[i] != '0' && charArray[i] != '1') {
                return false;
            }
        }
        for (int i = 1; i < charArray.length; i += 2) {
            if (charArray[i] != '|' && charArray[i] != '&' && charArray[i] != '^') {
                return false;
            }
        }
        return true;
    }

    public static int dp(String str, boolean desire) {
        if (!check(str)) {
            return 0;
        }
        int N = str.length();
        char[] charArray = str.toCharArray();
        int[][] tMap = new int[N][N];
        int[][] fMap = new int[N][N];
        for (int i = 0; i < N; i += 2) {
            tMap[i][i] = charArray[i] == '1' ? 1 : 0;
            fMap[i][i] = charArray[i] == '1' ? 0 : 1;
        }
        for (int row = N - 3; row >= 0; row -= 2) {
            for (int col = row + 2; col < N; col += 2) {
                for (int i = row + 1; i < N; i += 2) {
                    switch (charArray[i]) {
                        case '&':
                            tMap[row][col] += tMap[row][i - 1] * tMap[i + 1][col];
                            break;
                        case '|':
                            tMap[row][col] += tMap[row][i - 1] * tMap[i + 1][col];
                            tMap[row][col] += tMap[row][i - 1] * fMap[i + 1][col];
                            tMap[row][col] += fMap[row][i - 1] * tMap[i + 1][col];
                            break;
                        case '^':
                            tMap[row][col] += tMap[row][i - 1] * fMap[i + 1][col];
                            tMap[row][col] += fMap[row][i - 1] * tMap[i + 1][col];
                            break;
                    }
                    switch (charArray[i]) {
                        case '&':
                            fMap[row][col] += fMap[row][i - 1] * tMap[i + 1][col];
                            fMap[row][col] += fMap[row][i - 1] * fMap[i + 1][col];
                            fMap[row][col] += tMap[row][i - 1] * fMap[i + 1][col];
                            break;
                        case '|':
                            fMap[row][col] += fMap[row][i - 1] * fMap[i + 1][col];
                            break;
                        case '^':
                            fMap[row][col] += tMap[row][i - 1] * tMap[i + 1][col];
                            fMap[row][col] += fMap[row][i - 1] * fMap[i + 1][col];
                            break;
                    }
                }
            }
        }
        if (desire) {
            return tMap[0][N - 1];
        } else {
            return fMap[0][N - 1];
        }

    }
}

【案例5】

【题目描述】【很重要】【编辑距离问题】

左神算法之中级提升班(9)_第6张图片

【思路解析】

这里可以使用dp动态规划,来进行寻找最小代价。

这里的i和j表示str1使用i个字符,完成str2的j个字符
分为以下情况
(1)str1使用i-1个字符完成str2的j-1个字符,再将str1第i个字符替换为str2第j个字符,如果相等就可以剩去替换的过程
(2)str1使用i-1个字符完成str2的j个字符,再将str1第i个字符删去
  (3) str1使用i个字符完成str2的j-1个字符,再添加str2的第j个字符
则str1使用i个字符,完成str2的j个字符的最小使用,则为上面的最小值

 【代码实现】

import java.util.Scanner;

/**
 * @ProjectName: study3
 * @FileName: Ex5
 * @author:HWJ
 * @Data: 2023/9/11 15:01
 */
public class Ex5 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String str1 = input.next();
        String str2 = input.next();
        int add = input.nextInt();
        int del = input.nextInt();
        int replace = input.nextInt();
        int ans = dp(str1, str2, add, del, replace);
        System.out.println(ans);
    }

    public static int dp(String str1, String str2, int add, int del, int replace){
        int N1 = str1.length();
        int N2 = str2.length();
        int[][] map = new int[N1 + 1][N2 + 1];
        for (int i = 1; i <= N2; i++) {
           map[0][i] = i * add;
        }
        for (int i = 1; i <= N1; i++) {
            map[i][0] = i * del;
        }
        for (int i = 1; i <= N1; i++) {
            for (int j = 1; j <= N2; j++) {
                // 这里的i和j表示str1使用i个字符,完成str2的j个字符
                // 分为以下情况
                // (1)str1使用i-1个字符完成str2的j-1个字符,再将str1第i个字符替换为str2第j个字符,如果相等就可以剩去替换的过程
                // (2)str1使用i-1个字符完成str2的j个字符,再将str1第i个字符删去
                //  (3) str1使用i个字符完成str2的j-1个字符,再添加str2的第j个字符
                // 则str1使用i个字符,完成str2的j个字符的最小使用,则为上面的最小值
                map[i][j] = map[i - 1][j] + del;
                map[i][j] = Math.min(map[i][j], map[i][j - 1] + add);
                map[i][j] = Math.min(map[i][j], map[i][j - 1] + str1.charAt(i - 1) == str2.charAt(j - 1) ? 0 : replace);
            }
        }
        return map[N1][N2];
    }

}

【案例6】

【题目描述】

左神算法之中级提升班(9)_第7张图片

【思路解析】

建立一个每个字符的词频表,然后从当前位置开始遍历每一个字符,经历一个字符就词频减1,当出现某个字符词频为0时,就在所有经历过的字符中,选择一个字典序最小的字符,然后删去除了他其他相同的字符,并删去在他之前的字符。直到所有字符的词频都为1.

【代码实现】

import java.util.Scanner;

/**
 * @ProjectName: study3
 * @FileName: Ex6
 * @author:HWJ
 * @Data: 2023/9/11 16:14
 */
public class Ex6 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String str = input.next();
        String s = delete(str);
        System.out.println(s);
    }
    public static String delete(String str){
        if (str.length() <= 1){
            return str;
        }
        // 这里假设字符的ascii码值最大为256;
        int[] map = new int[256];
        int max = 1;
        for (int i = 0; i < str.length(); i++) {
            map[str.charAt(i)] += 1;
            max = Math.max(max, map[str.charAt(i)]); 
        }
        if(max == 1){
            return str;
        }else {
            for (int i = 0; i < str.length(); i++) {
                map[str.charAt(i)] -= 1;
                if (map[str.charAt(i)] == 0){
                    int min = Integer.MAX_VALUE;
                    int index = -1;
                    for (int j = 0; j <= i; j++) {
                        min = Math.min(min, str.charAt(j));
                        index = min == str.charAt(j) ? j : index;
                    }
                    return String.valueOf(str.charAt(index)) +
                            delete(str.substring(index + 1).replace(String.valueOf(str.charAt(index)), ""));
                }
            }
        }
        return "";
    }
}

你可能感兴趣的:(算法,java,数据结构)