ACM模式java代码练习

15.神秘字符

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNextLine()) {
            int n = Integer.valueOf(sc.nextLine());
            for(int i = 0; i < n; i++) {
                String a = sc.nextLine();
                String b = sc.nextLine();
                StringBuilder sb = new StringBuilder();
                sb.append(a.substring(0, a.length() / 2));
                sb.append(b);
                sb.append(a.substring(a.length() / 2, a.length()));
                System.out.println(sb);
            }
        }
    }
}

16.位置互换

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int count = sc.nextInt();
        sc.nextLine(); //跳到count的下一行
        for(int i = 0; i < count; i++) {
            String s = sc.nextLine();
            StringBuilder sb = new StringBuilder(); //用StringBuilder存储,不用在原先基础上交换
            for(int j = 0; j < s.length(); j+=2) {
                sb.append(s.charAt(j + 1));
                sb.append(s.charAt(j));
            }
            System.out.println(sb.toString());
        }
    }
}

17.出栈合法性

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        while(sc.hasNext()) {
            int n = Integer.valueOf(sc.nextLine()); //入栈顺序 1 ~ n
            if(n == 0) break;
            String[] s = sc.nextLine().split(" ");
            int index = 0;
            Stack<Integer> stack = new Stack<>();
            
            for(int j = 1; j <= n; j++) {  // 1 ~ n入栈
                stack.push(j);
                
                // 当前出栈队列的索引位置 等于 栈顶元素时 出栈并使出栈队列索引+1
                while(!stack.isEmpty() && stack.peek() == Integer.valueOf(s[index])) {
                    stack.pop();
                    index++;
                }
            }
            
            // 最后看栈是否为空则得知出栈序列是否正确
            System.out.println(stack.isEmpty() ? "Yes" : "No");
        }
        sc.close(); //没有也正确
    }
}

18.链表的基本操作

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        LinkedList list = new LinkedList<>();
        String[] s = sc.nextLine().split(" "); //notice 
        list = init(s);
        int num = Integer.valueOf(sc.nextLine());
       // int initLine = 0;
       if(num == 0) return;
        while(sc.hasNextLine()) {
            String[] ss = sc.nextLine().split(" ");
            switch (ss[0]) {            //notice 
                case "get":
                    System.out.println(list.isEmpty() ? "get fail" : list.get(Integer.valueOf(ss[1]) - 1));
                    break;
                case "delete" :
                    int del_pos = Integer.valueOf(ss[1]);
                    if(del_pos > list.size())
                        System.out.println("delete fail");
                    else {
                        for(int i = del_pos; i < list.size(); i++) {
                            list.set(i - 1, list.get(i));  // notice 
                        }
                        list.removeLast();  //删除最后一位
                        System.out.println("delete OK");
                    }
                    break;
                case "insert" :
                    int pos = Integer.valueOf(ss[1]);
                    int data = Integer.valueOf(ss[2]);
                    if(pos - 1 > list.size())
                        System.out.println("insert fail");
                    else if(list.isEmpty()) {
                        list.add(data);
                        System.out.println("insert OK");
                    }else{
                        list.add(list.getLast());
                        for(int i = list.size() - 2; i - 1 >= pos - 1; i--) {
                            list.set(i, list.get(i - 1));
                        }
                        list.set(pos - 1, data);
                        System.out.println("insert OK");
                    }
                    break;
                case "show" :
                    if(list.isEmpty()) 
                        System.out.println("Link list is empty");
                    else {
                        for (int i = 0; i < list.size(); i++) {
                            System.out.print(list.get(i) + (i == list.size() - 1 ? "" : " ")); //notice 最后一位不用加空格
                        }
                        System.out.println();
                    }
                    break;
                default: break;     
            }
         //   if(initLine == num)
         //       break;
        }
        sc.close();
    }
    
    private static LinkedList init(String[] s) {
        LinkedList list = new LinkedList<>();
        for(int i = 1; i < s.length; i++) {
            list.addFirst(Integer.valueOf(s[i]));
        }
        return list;
    }
}

19.反转链表

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNextLine()) {
            String[] str = sc.nextLine().split(" ");
            if(Integer.valueOf(str[0]) == 0) {
                System.out.println("list is empty");
            }
            ListNode dummy = new ListNode(-1);
            ListNode cur = dummy;
            //构造链表
            for (int i = 1; i < str.length; i++) {
                ListNode temp = new ListNode(Integer.valueOf(str[i]));
                cur.next = temp;
                cur = cur.next;
                if (i == str.length - 1) cur.next = null;
            }
            //输出原函数
            ListNode pointer = dummy.next;
            while(pointer != null) {
                System.out.print(pointer.val + " ");
                pointer = pointer.next;
            }
            System.out.println();
            //反转链表
            ListNode prev = null;
            ListNode curr = dummy.next; //dummy.next 就是head节点
            ListNode temp = null;
            while(curr != null) {
                temp = curr.next;
                curr.next = prev;
                prev = curr;
                curr = temp;
            }
            //输出反转链表
            ListNode pointer2 = prev; //prev是反转后链表头结点
            while(pointer2 != null) {
                System.out.print(pointer2.val + " ");
                pointer2 = pointer2.next;
            }
            System.out.println();
        }
    }
}
class ListNode {
    public int val;
    public ListNode next;
    ListNode(int val) { this.val = val; }
}

20.删除重复元素

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNextInt()) {
            int n = sc.nextInt();
            if(n != 0) {
                int[] arr = new int[n];
                for(int i = 0; i < n; i++) {
                    arr[i] = sc.nextInt();
                }
                print(arr, arr.length);
                int t = fun(arr);
                print(arr, t);
            }else{
                System.out.println("list is empty");
                break;
            }
        }
    }
    private static int fun(int[] arr){
        int slow = 1, fast = 1;
        while(fast < arr.length) {
            if(arr[slow - 1] != arr[fast]) {
                arr[slow] = arr[fast];
                slow++;
            }
            fast++;
        }
        return slow;
    }
    
    private static void print(int[] arr, int len) {
        for(int i = 0; i < len; i++) {
            System.out.print(arr[i]);
            if(i != arr.length - 1) {
                System.out.print(" ");
            }
        }
        System.out.println();
    }
}

21. 构造二叉树(给你中序和前序遍历,写出后序遍历)

import java.util.*;
import java.lang.*;

class TreeNode{
    TreeNode left;
    TreeNode right;
    Character val;
    public TreeNode(Character val){
        this.val = val;
    }
}

public class Main{
    static Map<Character, Integer> map;
    static StringBuilder sb;
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNextLine()) {
            String[] input = sc.nextLine().split(" ");
            char[] preorder = input[0].toCharArray();
            char[] inorder = input[1].toCharArray();
            // 构造哈希映射,帮助我们快速定位根节点
            map = new HashMap<>();
            sb = new StringBuilder();
            TreeNode root = buildTree(preorder, inorder);
            getPostOrder(root);
            System.out.println(sb.toString());
        }
    }
    
    public static TreeNode buildTree(char[] preorder, char[] inorder) {
        for(int i = 0; i < inorder.length; i++) {
            map.put(inorder[i], i);
        }
        return myBuildTree(preorder, inorder, 0, preorder.length - 1, 0, inorder.length - 1);
    }
    
    private static TreeNode myBuildTree(char[] preorder, char[] inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) {
        if (preorder_left > preorder_right) {
            return null;
        }

        // 前序遍历中的第一个节点就是根节点
        char preorder_root = preorder[preorder_left];
        // 在中序遍历中定位根节点
        int inorder_root = map.get(preorder_root);
        
        // 先把根节点建立出来
        TreeNode root = new TreeNode(preorder_root);
        // 得到左子树中的节点数目
        int size_left_subtree = inorder_root - inorder_left;
        // 递归地构造左子树,并连接到根节点
        // 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
        root.left = myBuildTree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1);
        // 递归地构造右子树,并连接到根节点
        // 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
        root.right = myBuildTree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right);
        return root;
    }
    
    private static void getPostOrder(TreeNode root) {
        if(root == null) return;
        getPostOrder(root.left);
        getPostOrder(root.right);
        sb.append(root.val);
    }
}

22.二叉树的遍历

// 方法二:使用索引,简化构建树的过程
import java.util.Scanner;

public class Main {
    static class TreeNode {
        char val;
        int left;
        int right;

        public TreeNode(char val, int left, int right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
    }

    static TreeNode[] nodes;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        nodes = new TreeNode[n + 1];
        for (int i = 0; i < n; i++) {
            char val = sc.next().charAt(0);
            int left = sc.nextInt();
            int right = sc.nextInt();
            nodes[i + 1] = new TreeNode(val, left, right);
        }
        preOrderTraversal(1);
        System.out.println();
        inOrderTraversal(1);
        System.out.println();
        postOrderTraversal(1);
        System.out.println();
        sc.close();
    }

    private static void postOrderTraversal(int root) {
        if (root == 0)
            return;
        postOrderTraversal(nodes[root].left);
        postOrderTraversal(nodes[root].right);
        System.out.print(nodes[root].val);
    }

    private static void inOrderTraversal(int root) {
        if (root == 0)
            return;
        inOrderTraversal(nodes[root].left);
        System.out.print(nodes[root].val);
        inOrderTraversal(nodes[root].right);
    }

    private static void preOrderTraversal(int root) {
        if (root == 0)
            return;
        System.out.print(nodes[root].val);
        preOrderTraversal(nodes[root].left);
        preOrderTraversal(nodes[root].right);
    }

}

23.二叉树的高度

import java.util.*;
import java.lang.*;
 
class TreeNode{
    TreeNode left;
    TreeNode right;
    Character val;
    public TreeNode(Character val) {
        this.val = val;
    }
}
 
public class Main{
    static Map<Character, Integer> map;
    static StringBuilder sb;
     
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNextLine()) {
            sc.nextLine();
            char[] preorder = sc.nextLine().toCharArray();
            char[] inorder = sc.nextLine().toCharArray();
            // 构造哈希映射,帮助我们快速定位根节点
            map = new HashMap<>();
            sb = new StringBuilder();
            TreeNode root = buildTree(preorder, inorder);
            System.out.println(getHeight(root));
        }
    }
     
    public static TreeNode buildTree(char[] preorder, char[] inorder) {
        for(int i = 0; i < inorder.length; i++) {
            map.put(inorder[i], i);
        }
        return myBuildTree(preorder, inorder, 0, preorder.length - 1, 0, inorder.length - 1);
    }
     
    private static TreeNode myBuildTree(char[] preorder, char[] inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) {
        if (preorder_left > preorder_right) {
            return null;
        }
  
        // 前序遍历中的第一个节点就是根节点
        char preorder_root = preorder[preorder_left];
        // 在中序遍历中定位根节点
        int inorder_root = map.get(preorder_root);
         
        // 先把根节点建立出来
        TreeNode root = new TreeNode(preorder_root);
        // 得到左子树中的节点数目
        int size_left_subtree = inorder_root - inorder_left;
        // 递归地构造左子树,并连接到根节点
        // 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
        root.left = myBuildTree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1);
        // 递归地构造右子树,并连接到根节点
        // 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
        root.right = myBuildTree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right);
        return root;
    }
     
    private static int getHeight(TreeNode root){
        if(root == null) {
            return 0;
        }else{
            return Math.max(getHeight(root.left), getHeight(root.right)) + 1;
        }
    }
}

24.最长公共子序列

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in); 
            while(sc.hasNextLine()) {
                String[] str = sc.nextLine().split(" ");
                String str1 = str[0];
                String str2 = str[1];
                char[] s = str1.toCharArray();
                char[] t = str2.toCharArray();
                int n = s.length;
                int m = t.length;
                int[][] f = new int[n + 1][m + 1];
                for(int i = 0; i < n; ++i) {
                    for(int j = 0; j < m; ++j) {
                        f[i + 1][j + 1] = s[i] == t[j] ? f[i][j] + 1 : Math.max(f[i][j + 1], f[i + 1][j]);
                    }
                }
                System.out.println(f[n][m]);
        }
    }
}

26.不相同的字符串

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
            int n = sc.nextInt();
            sc.nextLine();
            for(int i = 0; i < n; i++) {
                String str = sc.nextLine();
                System.out.println(minOperations(str));
        }
    }
    public static int minOperations(String str) {
        int[] hashMap = new int[26];
        //初始化数组
        for(int i = 0; i < str.length(); i++) {   //遍历字符串
            int position = str.charAt(i) - 'a'; //寻找字符对应数组中的位置
            hashMap[position]++;
        }
        int charUserCount = 0;// 记录 26 个位置被使用的次数
        int result = 0;// 需要操作的次数
        // 遍历数组
        for(int i = 0; i < hashMap.length; i++) {
            if(hashMap[i] == 1) { // 字符只出现一次,不需要操作,占用掉一个位置
                charUserCount++;
            }
            if(hashMap[i] % 2 == 0) { // 字符出现偶数次,需要操作 n/2 次,并且占用 n / 2 个位置
                charUserCount += hashMap[i] / 2;
                result += hashMap[i] / 2;
            }
            if(hashMap[i] != 1 && hashMap[i] % 2 == 1) { // 字符出现奇数次,需要操作 n/2 次,并且占用 n / 2 + 1 个位置
                charUserCount += hashMap[i] / 2 + 1;
                result += hashMap[i] / 2;
            }
        }
        // 当所有字母都被占用的时候,那么就进入到第二种情况
        // 把所有多出来的字符全都转化成某一个字母,比如a
        // 此时的情况一定是a有n个,其他字母全是1个,我们只需要消除多余的a即可
        // 每次删掉两个a,再转化成一个a,这样操作一次就少一个a
        // 总会变成所有字母都只剩下一个的情况,即达成题意不重复
        if(charUserCount > 26) {
            result += charUserCount - 26;
        }
        return result;
    }
}

27.最长增长子序列

import java.util.*;

public class Main{
    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        sc.nextLine();
        for(int i = 0;i< n;i++){
            String s = sc.nextLine();
            s = s.replaceAll("[\\[\\]]","");
            String[] sArray = s.split(",");
            int[] nums  = new int[sArray.length];
            for(int j = 0;j < sArray.length;j++){
                nums[j] = Integer.parseInt(sArray[j]);
            }
            printMaxLen(nums);
        }
    }
    public static void printMaxLen(int[] nums){
        int n = nums.length, ans = 0;
        int[] f = new int[n];
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < i; j++) {
                if(nums[j] < nums[i]) {
                    f[i] = Math.max(f[i], f[j]);
                }
            }
            ans = Math.max(ans, ++f[i]);
        }
        System.out.println(ans);
        // int n = nums.length;
        // if(n == 0) return;
        // int[] d = new int[n];
        // Arrays.fill(d,1);
        // int res = 1;
        // for(int i = 1;i < n;i++){
        //     //必须和前面所有进行比较,注意初始值
        //     for(int j = 0;j < i;j++){
        //         if(nums[i] > nums[j]){
        //             d[i] = Math.max(d[i],d[j] + 1);
        //         }
        //     }
        //     res = Math.max(res,d[i]);
            
        // }
        // System.out.println(res);
    }
}

31.字符串的最大价值

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in); 
        String s = sc.nextLine();
        
        int[] count = new int[2];  //记录字符 0 ,1 的个数
        for(char c : s.toCharArray()) {
            count[c - '0']++;
        }
        
        System.out.println(Math.max(getValue('0', s, count), getValue('1', s, count)));
    }
    
    public static int getValue(char c, String s, int[] count) {
        int start = s.indexOf(c);
        int end = s.lastIndexOf(c);
        int num = (1 + count[c - '0']) * count[c - '0'] / 2;
        num += (1 + start) * start / 2;
        num += (s.length() - end) * (s.length() - end - 1) / 2;
        return num;
    }
}
/*
首先,使用 count 数组来记录字符 '0' 和 '1' 的个数。
对于每个字符 '0' 和 '1',都分别计算以其为分界的情况下的价值。

对于以字符 '0' 为分界的情况:

1. 找到第一个字符 '0' 出现的位置 start 和最后一个字符 '0' 出现的位置 end。
2. 计算连续字符 '0' 所对应的价值:(1 + count[c - '0']) * count[c - '0'] / 2,其中 count[c - '0'] 是字符 '0' 的个数。也就是将 '0' 之间的所有 ‘1’ 逻辑上删除。
3. 计算字符 '0' 之前连续字符 '1' 所对应的价值:(1 + start) * start / 2。
4. 计算字符 '0' 之后连续字符 '1' 所对应的价值:(s.length() - end) * (s.length() - end - 1L) / 2,这里要注意长度减1。

同样的,对于以字符 '1' 为分界的情况,重复上述步骤。

最后,从这两种情况中选择较大的一个作为最终的最大价值。
*/

33.逛街(单调栈问题)

import java.util.*;

/*

题意为计算在每栋楼的位置处可以看到多少栋楼,考虑了从左向右和从右向左两个方向的可见性。可以使用单调栈的特性进行解决。

这里是代码的主要思路:

首先将 ans 每个位置上的值加 1(因为包括自己本身的楼)。

从左向右遍历楼的高度数组 buildings,使用栈 stack1 来保存之前遇到的楼的高度,
保证栈顶元素总是比后面的元素要高。在遍历过程中,对于每一栋楼,
将栈的大小(即之前楼的数量)存储在 ans 数组中的对应位置,
表示往左看能看到的楼的数量。如果当前楼高度大于等于栈顶元素,则不断将栈顶元素弹出
,直到满足条件。

从右向左遍历楼的高度数组 buildings,使用栈 stack2 来保存之前遇到的楼的高度,
保证栈顶元素总是比后面的元素要高。在遍历过程中,对于每一栋楼,将栈的大小
(即之前楼的数量)加到 ans 数组中的对应位置,表示往右看能看到的楼的数量
。如果当前楼高度大于等于栈顶元素,则不断将栈顶元素弹出,直到满足条件。

*/
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String str = scanner.nextLine();
        int[] buildings = parseIntArray(str);
        int n = buildings.length;
        int[] ans = new int[n];
        Arrays.fill(ans, 1);
        calculateVisibleCounts(buildings, ans);
        System.out.println(Arrays.toString(ans).replaceAll(" ", ""));
    }

    public static void calculateVisibleCounts(int[] buildings, int[] ans) {
        int n = buildings.length;
        Deque<Integer> stack1 = new ArrayDeque<>();
        Deque<Integer> stack2 = new ArrayDeque<>();

        for (int i = 0; i < n; i++) {   //从左到右
            ans[i] += stack1.size();
            while (!stack1.isEmpty() && stack1.peek() <= buildings[i]) {
                stack1.pop();
            }
            stack1.push(buildings[i]);
        }

        for (int i = n - 1; i >= 0; i--) {  //从右到左
            ans[i] += stack2.size();
            while (!stack2.isEmpty() && stack2.peek() <= buildings[i]) {
                stack2.pop();
            }
            stack2.push(buildings[i]);
        }
    }

    public static int[] parseIntArray(String input) {
        String[] str = input.substring(1, input.length() - 1).split(",");
        int[] arr = new int[str.length];
        for (int i = 0; i < str.length; i++) {
            arr[i] = Integer.parseInt(str[i]);
        }
        return arr;
    }
}

34.大鱼吃小鱼

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        sc.nextLine();
        List<Integer> list = new LinkedList<>();
        for(int i = 0; i < n; i++) {
            list.add(sc.nextInt());
        }
        int count = 0;
        while(!isIncreasing(list)) { //递增就是终止条件
            for(int i = list.size() - 1; i >= 1; i--) {
                if(list.get(i) < list.get(i - 1)) { // 如果右边的小于左边的,会被吃掉

                    list.remove(i);
                }
            }
            count++;
        }
        System.out.println(count);
    }
    
    public static boolean isIncreasing(List<Integer> list) {
        for(int i = 1; i < list.size(); i++) {
            if(list.get(i - 1) > list.get(i)) {
                return false;
            }
        }
        return true;
    }
}

35.打印二维数组

/**
 * 思路:
 * 第一步:
 * 1. 沿着第一行从左到右进行循环
 * 2. 然后沿着从右上到左下的斜线进行填充
 *       ->
 * [1 ][2 ][4 ][0 ]
 * [3 ][5 ][0 ][0 ]   ↙
 * [6 ][0 ][0 ][0 ]
 * [0 ][0 ][0 ][0 ]
 * 
 * 第二步:
 * 1. 沿着最后一列从上到下进行循环
 * 2. 仍然沿着右上到左下的斜线进行填充
 *               |
 *               v
 * [1 ][2 ][4 ][7 ]  
 * [3 ][5 ][8 ][11]  ↙
 * [6 ][9 ][12][14]
 * [10][13][15][16]
 * 
 * 思路有了,接下来需要解决的问题:
 * 1. 填充的数字是多少
 *    从规律上看数字是递增的,可以使用一个 count 变量
 *    进行标记,填充一次 +1
 * 2. 外层循环和内层循环的条件
 *    第一步:
 *       外层循环:第一行从左到右循环到最后一列
 *       内层循环:填充的元素位置不越界就可以一直沿着
 *       斜线进行填充
 *    第二步:
 *       外层循环:最后一列从上到下循环到最后一行
 *       内层循环:同第一步
 */
import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[][] array = new int[n][m];
        int count = 1;
        //第一步
        //第一行从左到右进行遍历(不包括对角线)
        for(int i = 0; i < m - 1; i++) {
            int currentY = i;
            int currentX = 0;
            //保证填充的元素位置不越界
            while(currentX != n && currentY != - 1) {
                array[currentX][currentY] = count;
                count++;
                currentX++;
                currentY--;
            }
        }
        //第二步
        //最后一列从上到下进行遍历(包括对角线)
        for(int i = 0; i < n; i++) {
            int currentX = i;
            int currentY = m - 1;
            while(currentY != -1 && currentX != n) {
                array[currentX][currentY] = count;
                count++;
                currentX++;
                currentY--;
            }
        }
        //打印数组
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
                System.out.printf("%d ", array[i][j]); //%d : 输出十进制整数
            }
            System.out.println();
        }
    }
}

36.网格路径和

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String arrayString = sc.next();
        int[][] grid = parse2dArray(arrayString);
        System.out.println(maxPathSum(grid));
    }    
    
    public static int maxPathSum(int[][] grid) {
        int n = grid.length;
        int m = grid[0].length;
        int[][] dp = new int[n][m];
        dp[0][0] = grid[0][0];
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
                if(i == 0 && j == 0) continue; //起点
                else if(i == 0) {
                    dp[i][j] = dp[i][j - 1] + grid[i][j];
                }else if(j == 0){
                    dp[i][j] = dp[i - 1][j] + grid[i][j];
                }else 
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }
        return dp[n - 1][m - 1];
    }
    
    
    // 将字符串解析为二维数组
    public static int[][] parse2dArray(String arrayString) {
        String[] strs = arrayString.substring(2, arrayString.length() - 2).split("],");
        // "[[1,2,3],[2,3,4],[3,4,5]]" -> "1,2,3", "[2,3,4", "[3,4,5"
        int rows = strs.length;
        int cols = strs[0].split(",").length;
        int[][] grid = new int[rows][cols];
        for(int i = 0; i < rows; i++) {
            String str = strs[i].replaceAll("\\[", ""); //去除所有左中括号
        //    "[3,4,5" - >  "3,4,5"
            String[] elements = str.split(",");
        //    "3,4,5" - > 3 4 5
            for(int j = 0; j < cols; j++) {
                grid[i][j] = Integer.parseInt(elements[j]);
            }
        }
        return grid;
    }
}

37.交换字符

import java.util.*;
/**
 * 思路:贪心算法
 * 
 * 首先对 01 串进行分析,当字符串长度为奇数时,最终的字符串
 * 一定以比较多的那个字符开头结尾。当字符串长度为偶数时,最终的
 * 字符串开头可能是'1' 也有可能是 '0'。此时,我们已经知道了
 * 目标字符串的样子。
 * 
 * 下一步的问题是如何以最小的次数将当前的字符串通过题目中的
 * 相邻字符相互交换的操作变为目标字符串。
 * 
 * 将一个字符从 i 位置移动到 j 位置,所需最低的次数是abs(i - j)
 * i 是当前位置,j 是最终位置。
 * 
 * 明确了最终的目标字符串,以及移动的次数了以后,选择的贪心策略是
 * 从头开始遍历字符串,选择目标字符,将其移动到最近的目标位置,
 * 记录其花费的次数。
 * 
 * 这个贪心策略的合理性在于,让每个字符都移动到距离它最近的位置,
 * 通过局部最优的移动策略得到总体最优的移动策略。
 * 
 * 以'1'和'0'分别为目标字符遍历一次后,
 * 根据二者的数量关系,确定最终的答案。
 */
public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        // 统计字符串中 '0' 和 '1' 的出现次数
        int count0 = 0;
        int count1 = 0;
        for(int i = 0; i < s.length(); i++) {
            if(s.charAt(i) == 0)
                count0++;
            else
                count1++;
        }
        long swap0 = countSwap(s, '0');
        long swap1 = countSwap(s, '1');
        if(count0 > count1){
            System.out.println(swap0);
        }else if(count0 < count1) {
            System.out.println(swap1);
        }else{
            System.out.println(Math.min(swap1,swap0));
        }
    }
    
    public static long countSwap(String s, char c) {
        int currentSwapIndex = 0; //需要交换到的索引位置
        long swaps = 0;            //交换次数统计
        for(int i = 0; i < s.length(); i++) {
            if(s.charAt(i) == c) {
                swaps += Math.abs(i - currentSwapIndex);
                currentSwapIndex += 2;
            }
        }
        return swaps;
    }
}

38.填充矩阵(螺旋矩阵)

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[][] matrix = generateMatrix(n, m);
        printMatrix(matrix, n, m);
    }
    
    public static int[][] generateMatrix(int n, int m) {
        int[][] res = new int[n][m];
        int u = 0;
        int d = n - 1;
        int l = 0;
        int r = m - 1;
        int num = n * m + 1;
        while(true) {
            for(int i = l; i <= r; i++) res[u][i] = --num;
            if(++u > d) break;
            for(int i = u; i <= d; i++) res[i][r] = --num;
            if(--r < l) break;
            for(int i = r; i >= l; i--) res[d][i] = --num;
            if(--d < u) break;
            for(int i = d; i >= u; i--) res[i][l] = --num;
            if(++l > r) break;
        }
        return res;
    }
    
    public static void printMatrix(int[][] matrix, int n, int m) {
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
                System.out.printf("%d ", matrix[i][j]);
            }
            System.out.println();
        }
    }
}

39.求和(回溯)

import java.util.*;
/**
 * 思路:回溯算法
 * 
 * 确定递归函数的参数列表
 * 
 *   backtracking(int index, int sum)
 *   index: 用于标记当前编辑到数的位置
 *   sum: 当前累积的和
 * 
 * 终止条件
 * 
 *   当 sum 大于所需要的值时就终止
 * 
 * 遍历方式:
 *   
 *   按照树形结构的遍历方式进行遍历
 */
public class Main{
    static ArrayList<Integer> list;
    static int m, n;
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        list = new ArrayList<>();
        backtracking(1, 0);
        list.clear();
    } 
    // 回溯函数,index 是当前要考虑的数字,sum 是当前组合的和
    public static void backtracking(int index, int sum){
        if(sum > m) {
            return; // // 如果当前和已经大于目标和,返回,不再继续搜索
        }
        if(sum == m) {
            // 如果当前和等于目标和,打印当前组合
            for(int i = 0; i < list.size() - 1; i++) {
                System.out.print(list.get(i) + " ");
            }
            System.out.println(list.get(list.size() - 1));
        }
        for(int i = index; i <= n && sum + i <= m; i++) {
            // 从当前数字开始尝试添加到组合中
            list.add(i); // 添加当前数字到组合中
            backtracking(i + 1, sum + i); // 递归搜索下一个数字
            list.remove(list.size() - 1); // 回溯,将当前数字移出组合
        }
    }
}

40.到达目的地的最短距离(动态规划)

/**
 * 思路:使用动态规划解决
 * 
 * 确定 dp 数组以及下标的含义
 * 
 *   设 dp[i] 表达到 i 点的最少步数
 * 
 * 考虑状态转移方程
 * 
 *   一、如果当前的位置能够被 2 整除,只有一种走法
 *     从别的位置,通过在数轴上移动到当前位置数值的两倍方式移动过来的。
 *     dp[i] = dp[i / 2] + 1;
 * 
 *   二、如果当前的位置不能被 2 整数,有两种走法
 *     1. 通过在数轴上向前移动一格的方式移动过来的
 *     2. 通过在数轴上向后移动一格的方式移动过来的
 *     
 *     dp[i] = Math.min(dp[i - 1], dp[(i + 1) / 2] + 1) + 1
 *   
 *     第 1 种走法为 dp[i - 1] 不难理解
 *     为什么第 2 种走法会是 dp[(i + 1) / 2] + 1 呢?
 *     因为如果当前位置不能被整除,那么这个位置的后一个位置必定能被整除,能被整除的坐标参考能被整除的走法。
 * 
 * 数组初始化
 *   
 *   1. 不要移动的情况 dp[0] = 0
 *   2. 只移动一步的情况 dp[1] = 1
 * 
 * 遍历顺序
 * 
 *   遍历方式比较简单,从前向后遍历就可以
 */
import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int x = sc.nextInt();
        System.out.println(solve(x));
    }
    
    public static int solve(int x) {
        if(x < 2 && x >= 0) {
            return x;
        }
        if(x < 0) {
            x = -x; //负整数结果与正整数结果一样
        }
        int[] dp = new int[x + 1];
        dp[0] = 0;
        dp[1] = 1;
        for(int i = 2; i <= x; i++) {
            if(i % 2 == 0) {
                dp[i] = dp[i / 2] + 1;
            }else{
                dp[i] = Math.min(dp[i - 1], dp[(i + 1) / 2] + 1) + 1;
            }
        }
        return dp[x];
    }
}

41.岛屿数量

import java.util.*;

public class Main{
    static int[][] grid;
    static int res;
    public static void main(String[] args) {
        res = 0;
        Scanner sc = new Scanner(System.in);
        int m = sc.nextInt();
        int n = sc.nextInt();
        int count = sc.nextInt();
        grid = new int[m][n];
        for(int i = 0; i < count; i++) {   //每次输入一个坐标,输入count次
            grid[sc.nextInt()][sc.nextInt()] = 1;
            for(int j = 0; j < m; j++)      {
                for(int k = 0; k < n; k++)      {
                    if(grid[j][k] == 1) {
                        dfs(grid, j, k);
                        res++;
                    }
                }
            }
        System.out.printf("%d ", res);
        for(int j = 0; j < m; j++) {      //将每一次的坐标标记为2的进行还原
            for(int k = 0; k < n; k++) {
                if(grid[j][k] == 2) {
                    grid[j][k] = 1;
                }
            }
        }
        res = 0;    //重置每一次的res
        }
    }
        
    public static void dfs(int[][] grid, int r, int c) {
        if(!inArea(grid, r, c)) {
            return;
        }
        if(grid[r][c] != 1) { //1表示陆地(未遍历)
            return ;
        }
        grid[r][c] = 2; //2表示陆地(已遍历)
        dfs(grid, r - 1, c);
        dfs(grid, r + 1, c);
        dfs(grid, r, c - 1);
        dfs(grid, r, c + 1);
    }
 
    public static boolean inArea(int[][] grid, int r, int c) {
        return r >= 0 && r < grid.length && c >= 0 && c < grid[0].length;
    }
}

42.汽水瓶换饮料

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            int emptyBottles = scanner.nextInt();
            if (emptyBottles == 0) {
                break;
            }
            System.out.println(maxSodaBottles(emptyBottles));
        }
    }
    public static int maxSodaBottles (int n) {
        int totalSodas = 0;
        while (n >= 3) {
            int newSodas = n / 3;  // 手里的空瓶能够换取多少瓶饮料
            totalSodas += newSodas;  // 喝掉用兑换的所有饮料
            n = n % 3 + newSodas;  // 新的空瓶总数 = 未能兑换的空瓶 + 喝完饮料后剩下的空瓶
        }
        if (n == 2) {  // 还剩两个空瓶的时候找老板借一个空瓶
            totalSodas += 1;
        }
        return totalSodas;
    }
}

44.开发商购买土地

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[][] arr = new int[n][m];
        int count = 0;              //所有的元素和
        for(int i = 0; i < n; i++) {     //转换为二维数组求解
            for(int j = 0; j < m; j++) {
                arr[i][j] = sc.nextInt();
                count += arr[i][j];
            }
        }
        int a = 0;
        int b = 0;
        int res = Integer.MAX_VALUE;
        int res1 = Integer.MAX_VALUE;
        int res2 = Integer.MAX_VALUE;
        int remain = 0;     //另一半的值, a为一边的值
        for(int j = 0; j < n; j++) {  //按照 列 分
            for(int k = 0; k < m; k++) {
                a += arr[j][k];
            }
            remain = count - a;
            res1 = Math.min(res1, Math.abs(remain - a));
        } 
        
        for(int j = 0; j < m; j++) {  //按照 列 分
            for(int k = 0; k < n; k++) {
                b += arr[k][j];
            }
            remain = count - b;
            res2 = Math.min(res2, Math.abs(remain - b));
        }
        res = Math.min(res1, res2);
        System.out.println(res);
    }
}

45.虚拟棋盘对战(动态规划)

/**
 * 思路:动态规划
 * 用F[l][r]表示先选的人能拿到的最高分
 * 用S[l][r]来表示后选的人能拿到的最高分
 * 对于先选者,有两种选法
 *     若先选者选A[0],则对于后面的1, ... ,n-1 数组,他就变成了后选者,此时能拿到的分为A[0]+S[1][n-1]
 *     若先选者选A[n-1],则对于前面的数组0,...,n-2,同样变为后选者,此时能拿到得分为A[n-1]+S[0][n-2];
 *     所以 F[0][n-1] = max(A[0]+S[1][n - 1],A[n - 1]+S[0][n - 2])
 * 对于后选者,他能能到的最高分是受先选者控制的,即他只能选到先选者留给他的最小值,将其转化为数学形式就是
 * S[l][r] = min(F[l + 1][r], F[l][r - 1]),因为先选者很聪明,肯定会把最低的分数留给他
*/
import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] array = new int[n];
        for(int i = 0; i < n; i++) {
            array[i] =sc.nextInt();
        }
        System.out.println(findMaxScore(array, n));
    }
    
    public static int findMaxScore(int[] A, int n) {
        int[][] F = new int[n][n];      //用F[l][r]表示先选的人能拿到的最高分
        int[][] S = new int[n][n];      //用S[l][r]表示后选的人能拿到的最高分
        for(int r = 0; r < n; r++) {
            F[r][r] = A[r]; //      [a][b]表示范围 a - b
            S[r][r] = 0;
            for(int l = r - 1; l >= 0; l--) {  //从右往左遍历  l--;
                F[l][r] = Math.max(A[l] + S[l+ 1][r], A[r] + S[l][r - 1]);
                S[l][r] = Math.min(F[l + 1][r], F[l][r - 1]);
            }
        }
        return Math.max(F[0][n - 1], S[0][n - 1]);
    }
}

46.携带研究材料(01背包问题)

一维DP

import java.util.Scanner;
 
public class Main {
    public static void main(String[] args) {
        // 读取 N
        Scanner scanner = new Scanner(System.in);
        int M = scanner.nextInt();
        int V = scanner.nextInt();
        int[] weights = new int[M];
        int[] values = new int[M];
 
        for (int i = 0; i < M; i++) {
            weights[i] = scanner.nextInt();
        }
        for (int j = 0; j < M; j++) {
            values[j] = scanner.nextInt();
        }
 
        // 创建一个动态规划数组dp,初始值为0
        int[] dp = new int[V + 1];
 
        // 外层循环遍历每个类型的研究材料
        for (int i = 0; i < M; ++i) {
            // 内层循环从 N 空间逐渐减少到当前研究材料所占空间
            for (int j = V; j >= weights[i]; --j) {
                // 考虑当前研究材料选择和不选择的情况,选择最大值
                dp[j] = Math.max(dp[j], dp[j - weights[i]] + values[i]);
            }
        }
 
        // 输出dp[N],即在给定 N 行李空间可以携带的研究材料最大价值
        System.out.println(dp[V]);
    }
}

二维DP

import java.util.*;

public class Main {
    
    public static void main(String[] args) {
        // 背包容量 N
        // 物品种类 M
        Scanner sc = new Scanner(System.in);
        
        int M = sc.nextInt();
        int N = sc.nextInt();
        
        int[] values = new int[M];
        int[] weights = new int[M];
        
        for(int i = 0; i < M;i++) {
            weights[i] = sc.nextInt();
        }
        
        
        for(int i = 0; i < M;i++) {
            values[i] = sc.nextInt();
        }
        
        int[][] dp = new int[M][N+1];
        
        // 初始化
        for(int i = weights[0]; i <= N; i++) {   //重点中的重点
            dp[0][i] = values[0];       //初始化第一行(不同容量只选第一个物品)
        }                               //其余第一列及其容量小于第一个物品容量的都为0
        
        // 先物品
        for(int i = 1; i < M; i++) { // 遍历科研物品
            // 后背包
            for(int j = 0; j <= N; j++) { // 遍历行李箱容量
                // 如果装不下这个物品,那么就继承dp[i - 1][j]的值
                if(weights[i] > j) {
                    dp[i][j] = dp[i-1][j];
                } else {
                    dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-weights[i]] + values[i]);
                }
            }
        }
        System.out.println(dp[M-1][N]);
    }
}

48.安排讲座

/**
 * 思路:贪心算法
 * 
 * 贪心的思路是每次选择局部最优解,最终达到全局最优解。
 * 在这个问题中,我们希望尽可能多的安排讲座,因此我们需要选择班级的课余时间段来最大化讲座的数量。
 * 
 * 首先,对班级课余时间段进行排序,按结束时间从小到大排序。
 * 这是希望选择结束时间早的班级,以便留更多的时间给其他班级。
 * 
 * 其次,初始化一个计数器 count 为 0,表示当前安排的讲座为 0,
 * 以及一个变量 end,表示当前已经安排的讲座的结束时间。
 * 
 * 遍历排序后的课余时间段信息:
 *   if (当前班级的开始时间 >= 已经安排的讲座结束时间) {
 *       安排的讲座数量++;
 *       将已经安排的讲座结束时间设置为当前班级的结束时间;
 *   }
 */
import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[][] schedules = new int[n][2];
        for(int i = 0; i < n; i++){
            schedules[i][0] = sc.nextInt();
            schedules[i][1] = sc.nextInt();
        }
        System.out.println(maxCount(schedules));
    }
    
    public static int maxCount(int[][] schedules) {
        Arrays.sort(schedules, (a, b) -> a[1] - b[1]);  //二维数组根据结束时间从小到大排序
        int count = 0; //   计数
        int end = 0;   //   当前已经安排的讲座的结束时间
        for(int i = 0; i < schedules.length; i++) {
            if(end <= schedules[i][0]){ //if (当前班级的开始时间 >= 已经安排的讲座结束时间) {
                count++;                //安排的讲座数量++;
                end = schedules[i][1]; // 时间点往后推
            }
        }
        return count;
    }
}

50.随机数排序(相同元素去重问题)

Treeset能够自动排序 + 去重

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        Set<Integer> uniqueNumbers = new TreeSet<>(); //TreeSet能够自动去重 + 自动排序
        for(int i = 0; i < n; i++) {
            int num = sc.nextInt();
            uniqueNumbers.add(num);
        }
        for(int num : uniqueNumbers) {
            System.out.printf("%d ", num);
        }
        System.out.println();
    }
}

双指针

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] nums = new int[n];
        for(int i = 0; i < n; i++) {
            nums[i] = sc.nextInt();
        }
        Arrays.sort(nums);
        //双指针解决
        int l = 0;
        int r = 1;
        //要求删除重复元素,实际上就是将不重复的元素移到数组的左侧。
        while(r < n){
            if(nums[l] != nums[r]) {
                nums[l + 1] = nums[r];
                l++;
            }
            r++;
        }
        
        int[] res = new int[l + 1];  // l + 1 为新数组长度
        for(int i = 0; i < l + 1; i++) {
            res[i] = nums[i];
        }
        for(int num : res){
            System.out.printf("%d ", num);
        }
        System.out.println();
    }
}

52.携带研究材料||(完全背包问问题)

一维DP

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int M = sc.nextInt();
        int V = sc.nextInt();
        int[] weights = new int[M];
        int[] values = new int[M];
        for(int i = 0; i < M; i++) {
            weights[i] = sc.nextInt();
            values[i] = sc.nextInt();
        }
        
        int[] dp = new int[V + 1];
        for(int i = 0; i < M; i++) {                //先遍历物品
            for(int j = weights[i]; j <= V; j++) {   //再遍历背包
                dp[j] = Math.max(dp[j], dp[j - weights[i]] + values[i]);
            }
        }
        System.out.println(dp[V]);
    }
}

 54.替换数字(字符串替换问题)

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        System.out.println(replaceNumber(s));
    }
    
    public static String replaceNumber(String s) {
        int count = 0;          //统计数字的个数
        int oldSize = s.length();   //原先字符串长度
        for(int i = 0; i < oldSize; i++) {
            if(Character.isDigit(s.charAt(i))) {
                count++;
            }
        }
        char[] newCharArray = new char[oldSize + count * 5];
        int newSize = newCharArray.length;  //目标字符串长度
        System.arraycopy(s.toCharArray(), 0, newCharArray, 0, oldSize);
        for(int i = newSize - 1, j = oldSize - 1; j < i; j--, i--) {    //从后往前遍历
            if(!Character.isDigit(newCharArray[j])) {    //不是数字
                newCharArray[i] = newCharArray[j];
            }else{
                newCharArray[i] = 'r';
                newCharArray[i - 1] = 'e';
                newCharArray[i - 2] = 'b';
                newCharArray[i - 3] = 'm';
                newCharArray[i - 4] = 'u';
                newCharArray[i - 5] = 'n';
                i -= 5;
            }
        }
        return new String(newCharArray);
    }
}

56.携带矿石资源(多重背包问题)

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int V = sc.nextInt();
        int M = sc.nextInt();
        int[] weights = new int[M];
        int[] values = new int[M];
        int[] counts = new int[M];
        for(int i = 0; i < M; i++) {
            weights[i] = sc.nextInt();
        }
        for(int i = 0; i < M; i++) {
            values[i] = sc.nextInt();
        }
        for(int i = 0; i < M; i++) {
            counts[i] = sc.nextInt();
        }
        int[] dp = new int[V + 1];
        for(int i = 0; i < weights.length; i++) {
            for(int j = V; j >= weights[i]; j--) {
                //多重背包就是 01背包 + 遍历个数
                for(int k = 1; k <= counts[i] && (j - k * weights[i]) >= 0; k++) {
                    dp[j] = Math.max(dp[j], dp[j - k * weights[i]] + k * values[i]);
                }
            }
        }
        System.out.println(dp[V]);
    }
}

57.爬楼梯(m个台阶,完全背包问题 )

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        int n = sc.nextInt();
        int m = sc.nextInt();
        System.out.println(climbStairs(n, m));
    }
    
    public static int climbStairs(int n, int m) {
        int[] dp = new int[n + 1];
        dp[0] = 1;
        
        for(int i = 1; i <= n; i++) {      //完全背包问题
            for(int j = 1; j <= m; j++) {
                if(i - j >= 0) {
                    dp[i] += dp[i - j];
                }
            }
        }
        return dp[n];
    }
}

58.区间和(前缀和数组降低复杂度)

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int size = scanner.nextInt();

        int[] numberArray = new int[size];
        for (int i = 0; i < size; i++) {
            numberArray[i] = scanner.nextInt();
        }

        // 计算前缀和数组
        int[] prefixArray = new int[size];
        prefixArray[0] = numberArray[0];
        for (int i = 1; i < numberArray.length; i++) {
            prefixArray[i] = prefixArray[i - 1] + numberArray[i];
        }
        // 计算区间和
        while (scanner.hasNextInt()) {
            int start = scanner.nextInt();
            int end = scanner.nextInt();
            System.out.println(calculateRangeSum(prefixArray, start, end));
            // System.out.println(calculateRangeSum2(numberArray, start, end));
        }
    }

    // 使用前缀和的方法(用end下标对应的数组元素和 - 区间外的元素和 = 区间元素和)
    public static int calculateRangeSum(int[] array, int start, int end) {
        int prefixSumStart = (start > 0) ? array[start - 1] : 0;
        return array[end] - prefixSumStart;
    }
}

超时写法

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] arr = new int[n];
        for(int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
        }
        while(sc.hasNextInt()) {
            int sum = 0;
            int a = sc.nextInt();
            int b = sc.nextInt();
            for(int i = a; i <= b; i++) {
                sum += arr[i];
            }
            System.out.println(sum);
        }
    }
}

60.匹配前缀的词典(Trie、字典树、前缀树)

import java.util.Scanner;

// 字典树的节点
class TrieNode {
    boolean isWord;
    final TrieNode[] children;
    public TrieNode() {
        isWord = false;
        children = new TrieNode[26];
    }
}

// 字典树
class Trie {
    TrieNode root;

    Trie() {
        root = new TrieNode();
    }

    public void insert(String word) {
        TrieNode current = root;
        for (int i = 0; i < word.length(); i++) {
            int c = word.charAt(i) - 'a';
            if (current.children[c] == null) {
                current.children[c] = new TrieNode();
            }
            current = current.children[c];
        }
        current.isWord = true;
    }

//    完整的字段树应该包含搜索功能,但是此处用不到
//    public boolean search(String word) {
//        TrieNode current = root;
//        for (int i = 0; i < word.length(); i++) {
//            int c = word.charAt(i) - 'a';
//            if (current.children[c] == null) {
//                return false;
//            }
//            current = current.children[c];
//        }
//        return current.isWord;
//    }

    public boolean startWith(String word) {
        TrieNode current = root;
        for (int i = 0; i < word.length(); i++) {
            int c = word.charAt(i) - 'a';
            if (current.children[c] == null) {
                return false;
            }
            current = current.children[c];
        }
        return true;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int m = scanner.nextInt();
        int n = scanner.nextInt();

        scanner.nextLine(); // 消耗掉换行符
        Trie trie = new Trie();
        for (int i = 0; i < m; i++) {
            trie.insert(scanner.nextLine());
        }

        for (int i = 0; i < n; i++) {
            boolean isStart = trie.startWith(scanner.nextLine());
            System.out.println(isStart);
        }
    }
}

62.平方差

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int L = sc.nextInt();
        int R = sc.nextInt();
        int ans = 0;
        for(;L <= R; L++) {
            //x = y^2 - z^2 = (y-z)(y+z)  x和y-z和y+z奇偶相同
            //当x为奇数,都可以满足
            //当x为偶数,需要是4的倍数
            if(L % 2 != 0 || L % 4 == 0){
                ans++;
            }
        }
        System.out.println(ans);    
    }
}

63.更小的数(动态规划)

 

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        boolean[][] dp = new boolean[s.length()][s.length()];
        //初始化
        for(int i = 0; i < s.length(); i++) {
            for(int j = 0; j <= i; j++) { //j <= i 则 false:初始化题解之外的情况
                dp[i][j] = false;  //i,j 表示子串区间
            }
        }
        int res = 0;
        //
        for(int i = s.length() - 2; i >= 0; i--) { //从后往前遍历
            for(int j = i + 1; j < s.length(); j++) {
                if(s.charAt(i) == s.charAt(j)) dp[i][j] = dp[i + 1][j - 1]; 
                //记住它,可以带入示例,i,j :0 5 与 1 4 都为true  
                if(s.charAt(i) > s.charAt(j)) dp[i][j] = true;
                if(s.charAt(i) < s.charAt(j)) dp[i][j] = false;
                if(dp[i][j] == true) res++;
            }
        }
        System.out.println(res); 
    }
}

65.买瓜(01背包 + 回溯)

import java.util.*;

public class Main{
    
    static int sum = Integer.MAX_VALUE; //刀数
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int target = sc.nextInt();
        int total = 0;
        int weight;
        double[] weights = new double[n * 2];
         for(int i = 0; i < n; i++) {
            weight = sc.nextInt();
            weights[i] = weight;
        }
        if(total < target) dfs(weights, target, 0, 0, 0);
        if(total == target) sum = 0;
        System.out.println(sum == Integer.MAX_VALUE ? -1 : sum);
    }
                                                                    //这次的n表示刀数
    public static void dfs(double[] weights, int target, double now_weight, int n, int index) {
        if(now_weight > target) {
            return;
        }
        if(now_weight == target) {
            sum = Math.min(sum, n);
            return;
        }
        for(int i = index; i < weights.length; i++) {
            dfs(weights, target, now_weight + weights[i], n, i + 1);
            dfs(weights, target, now_weight + weights[i] * 0.5, n + 1, i + 1);
        }
    }
}

67.异或和之和

 

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] arr = new int[n];
        int res = 0;
        
        for(int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
        }
        
        for(int i = 0; i < n; i++) {
            int segment_sum = 0;  //子段异或和
            for(int j = i; j < n; j++) {
                segment_sum ^= arr[j];
                res += segment_sum;
            }
        }
        System.out.println(res);
    }
}

68.像素放置(扫雷问题)

 

 

import java.util.*;

public class Main{
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        sc.nextLine();
        int[][] g = new int[n][m];
        for(int i = 0; i < n; i++) {
            String line = sc.nextLine();
            for(int j = 0; j < m; j++) {
                char c = line.charAt(j);
                if(c == '_') continue;
                g[i][j] = c - '0';
            }
        }
        int[] ans = new int[n];
        dfs(ans, g, n - 1);
        for(int x : ans) {
            printInt(x, m);
        }
    }
    
    static void printInt(int n, int m) {
        StringBuilder s = new StringBuilder();
        for(int i = 0; i < m; i++) {
            s.append(n >> i & 1); //将n右移i位和1 进行与运算
        }
        System.out.println(s);
    }
    
    static boolean dfs(int[] ans, int[][] g, int i) {
        int n = g.length, m = g[0].length;
        // 所有行的状态都枚举完毕且符合,返回true
        if (i < 0) return true;
        // 每一行都重新从0开始枚举状态
        for (ans[i] = 0; ans[i] < (1 << m); ans[i]++) {
            // 如果当前状态满足条件,则往上一行继续枚举
            if (check(ans, g, i) && dfs(ans, g, i - 1)) {
                return true;
            }
        }
        // 如果无法得到正确的排列,需要将此行重置,防止后续dfs时cnt计算错误
        ans[i] = 0;
        return false;
    }
    // 当枚举到第i行时,需要先校验第i行和第i+1行的数字是否满足
    static boolean check(int[] ans, int[][] g, int i) {
        int n = g.length, m = g[0].length;
        for (int j = 0; j < m; j++) {
            // 第i行
            if (g[i][j] > 0) {
                int c = cnt(ans, i, j);
                // 第0行特判,因为没有补救机会了,只能判断是否相等
                if (i == 0 && c != g[i][j]) return false;
                // 由于还有第i-1行没有枚举,所以第i行只判断是否大于(如果小于的话,在i-1行还有补救机会)
                if (i > 0 && c > g[i][j]) return false;
            }
            // 第i+1行
            if (i + 1 < n && g[i + 1][j] > 0) {
                int c = cnt(ans, i + 1, j);
                // 第i+1行的数字已经可以完整判断了,因为i,i+1,i+2这三行都已经枚举了状态
                if (c != g[i + 1][j]) return false;
            }
        }
        return true;
    }

    // 获取第i行第j列周围数字
    static int cnt(int[] ans, int i, int j) {
        int cnt = 0;
        for (int r = i - 1; r <= i + 1; r++) {
            if (r < 0 || r >= ans.length) continue;
            for (int c = j - 1; c <= j + 1; c++) {
                if (c < 0) continue;
                cnt += ans[r] >> c & 1;
            }
        }
        return cnt;
    }
}

 70.冶炼金属

 

 

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] arr1 = new int[n];
        int[] arr2 = new int[n];
        for(int i = 0; i < n; i++) {
            int x = sc.nextInt();
            int y = sc.nextInt();
            arr1[i] = x / y;
            arr2[i] = x / (y + 1);
        }
        int max = Integer.MAX_VALUE;
        int min = Integer.MIN_VALUE;
        for(int i : arr2) {
            min = Math.max(min, i + 1);
        }
        System.out.print(min + " ");
        for(int i : arr1) {
            max = Math.min(max, i);
        }
        System.out.println(max);
    }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值