Zuoshen Algorithm Intermediate Improvement Class (9)

Table of contents

【Case 1】

[Title description]

 [Analysis of ideas]

【Code】

【Case 2】

[Title description]

[Analysis of ideas, ordinary solution skills, key points of analyzing termination conditions from business]

【Code】

【Case 3】

[Title description]

[Analysis of ideas]

【Case 4】

[Title description]

 [Analysis of ideas]

【Code】

[Dynamic programming code]

【Case 5】

[Problem description] [Very important] [Edit distance problem]

[Analysis of ideas]

 【Code】

【Case 6】

[Title description]

[Analysis of ideas]

【Code】


【Case 1】

[Title description]

 [Analysis of ideas]

Because the number range can only be 1 - n, and the array range is 0 - n-1, so if there are no missing values, i + 1 should be placed at each i position, so we complete this operation directly for each array, Put i+1 in each i position as much as possible. If some positions are not i+1, then these positions are missing values, just traverse and print.

【Code】

/**
 * @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;
        }
    }

}

【Case 2】

[Title description]

[Idea analysis and  ordinary solution skills: analyze the key points of termination conditions from the business ]

It is easy to think of using violent recursion to solve this problem, but the restriction condition is only cur == end, which is not enough as a basecase. Additional restrictions need to be added, because end and start are both even numbers, and end >> start, so there is only one The trivial solution of reaching the end with likes, if it is higher than the cost solution, will not be considered directly.

From the business analysis, because he has a private message that can be -2, and then in the recursion, it has a branch that may always be -2, resulting in the end being unable to be reached, so the restriction condition is increased to stop when start is less than 0.

From the business analysis, he has a *2 method, but there is always a *2 that can make him bigger than b for the first time. At this time, if he *2 again, it will cost more private chat money, and then analyze *2 again will be greater than 2*b, so add a restriction that start cannot be greater than 2*b;

【Code】

/**
 * @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));
    }

}

【Case 3】

[Title description]

[Analysis of ideas]

You can generate a graph through the following correlation matrix, and then do a width-first traversal of the graph starting from the end H. Each node implements a hash table, and then maintains it in the hash table. When the number of days spent increases, the income will definitely increase, and then each The node gets its own hash table, and then finally sums up all the hash tables, so you get all the completion methods. Then finally check the table based on the number of restricted days. Finally, you can also use the big root heap here. Only the values ​​less than the limit number of days are added, and then the big root heap is maintained based on the size of the income. Both ways are pretty much the same.

【Case 4】

[Title description]

 [Analysis of ideas]

Because the operations & | ^ are all binary operations, the length of the expression should be an odd number and greater than 1, so that there are only 0 or 1 on the odd bits, and there are only &, | or ^ operators on the even bits. If this is not true, The string of the rule returns 0 directly.

Then there is the following definition of combination. For each certain expression combination, there should be certain brackets. For different bracket fillings, different combination methods are considered. Parentheses can be thought of as order regulations when performing operations, and it is not necessarily necessary to fill the string with parentheses.

【Code】

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;
    }
}

[Dynamic programming code]

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];
        }

    }
}

【Case 5】

[Problem description] [Very important] [Edit distance problem]

[Analysis of ideas]

Here you can use dp dynamic programming to find the minimum cost.

The i and j here indicate that str1 uses i characters to complete the j characters of str2. It is
divided into the following situations
(1) str1 uses i-1 characters to complete the j-1 characters of str2, and then replaces the i-th character of str1 with The jth character of str2, if they are equal, the replacement process can be left
(2) str1 uses i-1 characters to complete the j characters of str2, and then deletes the i-th character of str1
  (3) str1 uses i characters to complete j-1 characters of str2, and then add the j-th character of str2.
Then str1 uses i characters to complete the minimum use of j characters of str2, which is the minimum value above.

 【Code】

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];
    }

}

【Case 6】

[Title description]

[Analysis of ideas]

Establish a word frequency table for each character, and then traverse each character starting from the current position. After each character is experienced, the word frequency is reduced by 1. When a character's word frequency is 0, a dictionary order is selected among all experienced characters. The smallest character is then deleted, its other identical characters are deleted, and the characters before it are deleted. Until the word frequency of all characters is 1.

【Code】

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 "";
    }
}

Guess you like

Origin blog.csdn.net/weixin_73936404/article/details/132016074