备战蓝桥杯,用JAVA刷洛谷算法题单:【数据结构1-1】线性表

参考

【数据结构1-1】线性表 - 题单 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

image-20240308101831010

动态数组

P3613 【深基15.例2】寄包柜

使用了嵌套map来表示嵌套的kv对应,如果用list的话不能对应离散的kv,必须连续的(例如初始的时候加入第10个柜子第10号格子的物品,那List就要创建10大小,每次都要这样操作十分不便)。map就可以用来解决离散k+动态数组,十分的不错。

本来20%,仔细看了下题目有个k=0表示清空操作,补充了一下就AC了

package _1_1;

import java.io.*;
import java.util.HashMap;

public class P3613 {
    public static void main(String[] args) throws IOException {
        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        PrintWriter out = new PrintWriter(System.out);
        in.nextToken();
        int n = (int) in.nval;
        in.nextToken();
        int q = (int) in.nval;
        int op, i, j, k;

        // 用map来存储,key表示第几个柜子,value用一个map表示格子,key表示格子编号,value表示格子内容
        HashMap<Integer, HashMap<Integer, Integer>> map = new HashMap<>();
        while (q-- > 0) {
            in.nextToken();
            op = (int) in.nval;
            if (op == 1) {
                // 存,注意k==0表示清空格子
                in.nextToken();
                i = (int) in.nval;
                in.nextToken();
                j = (int) in.nval;
                in.nextToken();
                k = (int) in.nval;
                // 先判断柜子存不存在
                if (!map.containsKey(i)) {
                    // 创建柜子直接放入
                    HashMap<Integer, Integer> gezi = new HashMap<>();
                    gezi.put(j, k);
                    map.put(i, gezi);
                } else {
                    // 柜子i存在,判断格子j存不存在
                    HashMap<Integer, Integer> gezi = map.get(i);
                    if (!gezi.containsKey(j)) {
                        // 在原有格子map中放入新得key(这里容易混)
                        gezi.put(j, k);
                        map.put(i, gezi);
                    } else {
                        // 重复放入物品(这里会涉及到清空)
                        // 上面的操作都是直接放入k,就算k=0也不影响,但是重复是需要加法得
                        if (k != 0) {
                            Integer integer = gezi.get(j);
                            gezi.put(j, integer + k);
                        } else {
                            gezi.put(j, k);
                        }
                        map.put(i, gezi);
                    }
                }
            } else {
                // 查
                in.nextToken();
                i = (int) in.nval;
                in.nextToken();
                j = (int) in.nval;
                // 保证查询的柜子有存过东西,这里不用判断
                out.println(map.get(i).get(j));
            }
        }
        out.flush();
        out.close();
    }
}

使用LinkedList实现,注意add和poll同一个First或者Last

P1449 后缀表达式

知道后缀表达式怎么求结果即可,注意取出来后操作符的计算顺序

package _1_1.stack;

import java.util.LinkedList;
import java.util.Scanner;

public class P1449 {
    // algo 后缀表达式求结果值
    // 遇到操作数压入栈,遇到操作符,把栈中前两个数取出来计算,再把结果压入栈
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String line = scanner.nextLine();

        LinkedList<Integer> list = new LinkedList<>();
        int opNum = 0;
        for (char c : line.toCharArray()) {
            if (Character.isDigit(c)) {
                // !注意此处char-int
                opNum = opNum * 10 + c - '0';
            } else if (c == '.') {
                // 操作数读取结束,压入栈
                list.addLast(opNum);
                opNum = 0;
            } else if (c == '@') {
                // 结束符
                System.out.println(list.pollLast());
                break;
            } else {
                Integer num1 = list.pollLast();
                Integer num2 = list.pollLast();
                if (c == '+')
                    list.addLast(num1 + num2);
                else if (c == '-')
                    // 注意是 左操作数(后出的) - 右操作数(先出的)
                    list.addLast(num2 - num1);
                else if (c == '*')
                    list.addLast(num1 * num2);
                else
                    // 注意是 左操作数(后出的) / 右操作数(先出的)
                    list.addLast(num2 / num1);
            }
        }
        scanner.close();
    }
}

P1241 括号序列

一般WA,应该是题目没理解对,算了懒得。

package _1_1.stack;

import java.util.LinkedList;
import java.util.Scanner;

public class P1241 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder line = new StringBuilder(scanner.nextLine());
        for (int i = 0; i < line.length(); i++) {
            if (line.charAt(i) == ']') {
                // 往左找
                for (int j = i - 1; j >= 0; j--) {
                    if (line.charAt(j) == '[') {
                        // 这里用一个别的符号代替匹配的两个括号,防止length的问题
                        line.replace(j, j + 1, " ");
                        line.replace(i, i + 1, " ");
                        System.out.print("[]");
                        break;
                    } else if (line.charAt(j) == '(') {
                        break;
                    }
                    // 找到一个左括号就退出
                }
            } else if (line.charAt(i) == ')') {
                for (int j = i - 1; j >= 0; j--) {
                    if (line.charAt(j) == '(') {
                        // 这里用一个别的符号代替匹配的两个括号,防止length的问题
                        line.replace(j, j + 1, " ");
                        line.replace(i, i + 1, " ");
                        System.out.print("()");
                        break;
                    } else if (line.charAt(j) == '[') {
                        break;
                    }
                }
            }
        }
        // 把没匹配的手动匹配输出(这里要逆序)
        for (int i = line.length() - 1; i >= 0; i--) {
            char c = line.charAt(i);
            if (c != ' ') {
                if (c == '(' || c == ')') {
                    System.out.print("()");
                } else if (c == '[' || c == ']') {
                    System.out.print("[]");
                }
            }
        }
        scanner.close();
    }


    public static void fun() {
        Scanner scanner = new Scanner(System.in);
        // 没有匹配的要手动匹配输出,成功匹配的记得把栈里的取出来再输出,最后栈里剩下的也手动匹配输出
        String line = scanner.nextLine();
        // 一个栈只放未匹配左括号,一个放所有未匹配
        LinkedList<Character> left = new LinkedList<>();
        LinkedList<Character> all = new LinkedList<>();
        for (char c : line.toCharArray()) {
            if (c == '(' || c == '[') {
                left.addLast(c);
                all.addLast(c);
            } else {
                // 注意题目:中间可能配对失败,但是最后才是把所有没配对的手动配对,如([)[ - []()[]() 而不是()[][]()
                // 注意匹配成功后all中也要去除左括号,但是由于混放不知道左括号的位置,所以这道题感觉不如直接模拟
                if (c == ')') {
                    if (left.getLast() == '(') {
                        // 成功匹配
                        left.pollLast();
                        System.out.print("()");
                    } else {
                        // 没配对放入所有未匹配栈,左括号栈里面的不弹出
                        all.addLast(c);
                    }
                } else {
                    if (left.getLast() == '[') {
                        // 成功匹配
                        left.pollLast();
                        System.out.print("[]");
                    } else {
                        // 没配对放入所有未匹配栈,左括号栈里面的不弹出
                        all.addLast(c);
                    }
                }
            }
        }
        while (!all.isEmpty()) {
            Character c = all.pollLast();
            if (c == '(' || c == ')') {
                System.out.print("()");
            } else if (c == '[' || c == ']') {
                System.out.print("[]");
            }
        }
        scanner.close();
    }
}

队列

使用LinkedList实现,注意add和poll不同First和Last

BFS使用队列实现。

P1540 [NOIP2010 提高组] 机器翻译

package _1_1.queue;

import java.util.LinkedList;
import java.util.Scanner;

public class P1540 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        LinkedList<Integer> list = new LinkedList<>();
        int count = 0;
        for (int i = 1; i <= m; i++) {
            int k = scanner.nextInt();
            if (!list.contains(k)) {
                count++;
                // 查外村并且加入内存,如果内存满了就先去除最早的元素
                if (list.size() == n) {
                    list.removeFirst();
                }
                list.addLast(k);
            }
        }
        System.out.println(count);
        scanner.close();
    }
}

链表

使用LinkedList实现

P1996 约瑟夫问题

循环下标+标记数组

package _1_1.queue;

import java.util.Scanner;

public class P1996 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        // 记录是否已经出局
        boolean[] out = new boolean[n + 1];
        // algo 循环数组
        // index:1~n,所以index%(n+1)+1

        // 从第一个人之前开始
        int now = 0;
        // 出来n个人
        for (int i = 1; i <= n; i++) {
            // k表示当前报数
            int k = 1;
            while (k <= m) {
                now++;
                if (now == n + 1) now = 1;
                if (!out[now]) k++;
            }
            out[now] = true;
            System.out.printf("%d ", now);
        }
        scanner.close();

    }
}

链表

P2234 [HNOI2002] 营业额统计

解法1:平衡树

平衡树(AVL树) - 知乎 (zhihu.com)

平衡树【Splay树】学习小记-CSDN博客

解法2:看题干,就是要找和当前数最接近的那个数,Java中有个TreeMap,自带排序,就不用自己写list+sort+二分了,灵感来自题解中c++的lower_bound,Java中没有直接对应的,但是百度一下找到了TreeMap。

TreeMap用的红黑树实现(没学过,不会)。

TreeSet中有四个方法,分别可以获得当前指定值在有序序列中的最接近数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

详细可以见TreeMap的实现方法

image-20240308155334006

  • Ceiling表示返回>=k的最小值,不存在则返回null
  • Flooring表示返回<=k的最大值
  • Higher表示返回>k的最小值,不存在则返回null
  • Lower表示返回<k的最大值

还是很好用的,直接AC

package _1_1.Ttree;

import java.util.Scanner;
import java.util.TreeSet;

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

        TreeSet<Integer> treeSet = new TreeSet<>();
        int result = 0;
        Integer ceiling = 0, floor = 0, min = 0;
        while (n-- > 0) {
            int k = scanner.nextInt();
            // 注意先找min,再加入当前营业额
            if (treeSet.size() == 0) {
                // 第一天不用找
                result += k;
            } else {
                // algo TreeMap:最接近数
                // 找到最接近当前营业额的数,加入结果
                ceiling = treeSet.ceiling(k);
                floor = treeSet.floor(k);
                if (ceiling != null && floor != null) {
                    min = Math.min(Math.abs(ceiling - k), Math.abs(floor - k));
                } else if (ceiling != null) {
                    min = Math.abs(ceiling - k);
                } else if (floor != null) {
                    min = Math.abs(floor - k);
                }
                result += min;
            }
            // 把当前营业额加入序列
            treeSet.add(k);
        }
        System.out.println(result);
        
        scanner.close();
    }
}
;
                } else if (ceiling != null) {
                    min = Math.abs(ceiling - k);
                } else if (floor != null) {
                    min = Math.abs(floor - k);
                }
                result += min;
            }
            // 把当前营业额加入序列
            treeSet.add(k);
        }
        System.out.println(result);
        
        scanner.close();
    }
}
  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值