【A】1.2 链表

和数组不同的是,链表并不需要一块连续的内存空间,它可以通过指针将一组零散的内存块串联起来使用。链表的基本操作是最考验逻辑思维能力的,尤其需要注意:

  1. 浅拷贝相当于引用
  2. 哨兵/保护结点作为访问入口
  3. 边界与异常检查

AC136.邻值查找

对序列A中每一个数Ai,求在Ai前的数与Ai的最小差值,以及对应下标(若最小差值对应下标不唯一,则返回最小下标)。例如,输入1, 5, 3, 4, 2

treemap

一个可能的想法是,对前i个数维护一个有序集合,二分查找Ai的前驱与后继,比较差值,返回最小差值与对应下标:

1, 5:添加5,前驱为1,后继为\,最小差值为4,对应下标1
1,3,5:添加3,前驱为1,后继为5,最小差值为2,对应下标1
1,3,4,5:添加4,前驱为3,后继为5,最小差值为1,对应下标2
1,2,3,4,5:添加2,前驱为1,后继为3,最小差值为1,对应下标1

import java.io.*;
import java.util.Map;
import java.util.TreeMap;

public class Main {
    public static void main(String[] args) throws Exception {
        StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        BufferedWriter br = new BufferedWriter(new OutputStreamWriter(System.out));

        st.nextToken();
        int n = (int) st.nval;

        // 平衡树
        TreeMap<Integer, Integer> map = new TreeMap<>();
        for (int i = 1; i <= n; i++) {
            st.nextToken();
            int val = (int) st.nval;
            // 添加关键字和对应的值,即数值与下标
            map.put(val, i);
            if (i != 1) {
                // 返回大于等于 key 的最小元素
                Map.Entry<Integer, Integer> up = map.ceilingEntry(val + 1);
                // 返回小于等于 key 的最大元素
                Map.Entry<Integer, Integer> down = map.floorEntry(val - 1);
                int res = Integer.MAX_VALUE, pos = -1;
                if (down != null) {
                    res = val - down.getKey();
                    pos = down.getValue();
                }
                if (up != null && up.getKey() - val < res) {
                    res = up.getKey() - val;
                    pos = up.getValue();
                }
                br.write(res + " " + pos);
                br.newLine();
            }
        }
        br.flush();
    }
}

doubly-linked list

顺序添加元素可行,那倒序删除呢?依然是维护一个有序序列:

image

图1.2.1 样例及实现


  • 数组:按下标索引,记录每个下标对应的链表结点,便于快速访问
  • 双链表:按值排序,倒序考虑每个下标,前后比较,删除相应结点

注意,虽然Java内置LinkedList,但是容器接口没有暴露具体的实现方法,也无法获取前驱后继。
所以,双链表需要自己手动实现。

import java.io.*;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;


class Main {
    static int n;
    // 双链表,便于删除和查询前驱后继
    static Node head;
    static Node tail;
    // 数组,便于根据索引快速访问结点


    public static void main(String[] args) throws IOException {
        StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        st.nextToken();
        n = (int) st.nval;
        Node[] pile;
        pile = new Node[n + 1];

        // 虚拟/保护结点
        head = new Node(-1, -1);
        tail = new Node(-1, -1);
        // 空双链表初始化
        head.next = tail;
        tail.prev = head;

        // 按值排序
        Node[] nodes = new Node[n];
        for (int i = 1; i <= n; i++) {
            st.nextToken();
            Node node = new Node((int) st.nval, i);
            nodes[i - 1] = node;
            pile[i] = node;
        }
        Arrays.sort(nodes, (o1, o2) -> o1.val - o2.val);
        for (int i = n - 1; i >= 0; i--) {
            // 头插
            Node node = nodes[i];
            node.next = head.next;
            node.prev = head;
            head.next.prev = node;
            head.next = node;
        }

        Deque<String> stack = new ArrayDeque<>();
        for (int i = n; i >= 2; i--) {
            Node node = pile[i];

            int pos = -1;
            int diff = Integer.MAX_VALUE;

            // 优先考虑前驱
            if (node.prev != head) {
                diff = node.val - node.prev.val;
                pos = node.prev.index;
            }
            if (node.next != tail && node.next.val - node.val < diff) {
                diff = node.next.val - node.val;
                pos = node.next.index;
            }

            stack.push(diff + " " + pos);

            // 删除结点
            node.prev.next = node.next;
            node.next.prev = node.prev;
        }

        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        while (!stack.isEmpty()) {
            bw.write(stack.pop());
            bw.newLine();
        }
        bw.flush();
        bw.close();
    }

    static class Node {
        int val;
        int index;
        Node prev;
        Node next;

        public Node(int val, int index) {
            this.val = val;
            this.index = index;
        }
    }
}
posted @   安如衫  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示