题解 | #从单向链表中删除指定值的节点#

从单向链表中删除指定值的节点

https://www.nowcoder.com/practice/f96cd47e812842269058d483a11ced4f

import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNext()) { // 注意 while 处理多个 case
            String str = in.nextLine(); //获得输入
            String[] strs = str.split(" ");  //按空白拆分,方便处理
            int n = Integer.parseInt(strs[0]); //总结点数
            int firstValue = Integer.parseInt(strs[1]); //头节点值
            int aimValue = Integer.parseInt(strs[strs.length - 1]); //目标节点值
            LinkList ll = new LinkList(); //自定义链表
            ll.add(firstValue); //插入头节点
            for (int i = 2; i < strs.length - 1; i += 2) { //插入其他节点
                ll.addNext(Integer.parseInt(strs[i]), Integer.parseInt(strs[i + 1]));
            }
            if (ll.removeNode(aimValue)) { //删除目标节点
                ll.printNodeValue();
            }
            // System.out.println(a + b);
        }
    }


    public static void readLinkList(LinkList lastNode) {

    }

}

class LinkList { //自定义链表类
    int size = 0; //链表长度
    Node headNode; //头节点
    Node tailNode; //尾节点

    LinkList() { //无参构造
    }

    static class Node { //内部节点类
        int value; //节点值
        Node pre; //头指针
        Node curr; //尾指针
        Node(int value, Node pre, Node curr) { //构造
            this.value = value;
            this.pre = pre;
            this.curr = curr;
        }
        Node() {

        }
    }

    public boolean add(int val, int index) { //指定下标插入
        Node newNode = new Node(val, null, null); //新节点
        if (size == 0) { //判空
            headNode = newNode;
            tailNode = newNode;
            size++;
            return true;
        } else if (index < 0 || index > size + 2) { //判下标范围
            return false;
        } else if (index == 1) { //头节点位置直接插入
            newNode.curr = headNode;
            headNode.pre = newNode;
            headNode = newNode;
            size++;
            return true;
        } else if (index == size + 1) { //尾节点位置直接插入
            newNode.pre = tailNode;
            tailNode.curr = newNode;
            tailNode = newNode;
            size++;
            return true;
        } else { //中间位置
            Node preNode = null; //前一个
            Node currNode = headNode;//后一个(注意前后是挨着的,preNode->currNode)
            for (int i = 2; i <= index; i++) { //获得指定下标位置的节点currNode
                preNode = currNode;
                currNode = currNode.curr;
            }
            newNode.pre = preNode; 
            newNode.curr = currNode;
            preNode.curr = newNode;
            currNode.pre = newNode;//插入操作
            size++; //长度增加
            return true;
        }
    }
    public void add(int val) { //尾插法插入节点
        Node newNode = new Node(val, null, null);
        if (size == 0) { //判空
            headNode = newNode;
            tailNode = newNode;
            size++;
        } else {
            newNode.pre = tailNode;
            tailNode.curr = newNode;
            tailNode = newNode;
            size++;
        }
    }

    public boolean addNext(int val, int pre) { //题中指定插入方法,插入指定值的节点后面
        Node newNode = new Node(val, null, null);
        if (size == 0) { //判空
            return false;
        }
        Node preNode = null;
        Node currNode = headNode;
        for (int i = 0; i < size; i++) { //遍历链表找指定值节点
            if (currNode.value == pre) { //找到后处理
                newNode.pre = currNode;
                if (currNode.curr == null) { //判断是否为尾节点
                    currNode.curr = newNode;
                    size++;
                    return true;
                } else { //其他情况
                    newNode.curr = currNode.curr;
                    currNode.curr = newNode;
                    currNode = newNode;
                    size++;
                    return true;
                }
            }
            preNode = currNode;
            currNode = currNode.curr;
        }
        return  false;
    }

    public void printNodeValue() { //遍历链表并打印节点
        Node preNode = null;
        Node currNode = headNode;
        while (currNode.curr != null) {
            System.out.print(currNode.value + " ");
            preNode = currNode;
            currNode = currNode.curr;
        }
        System.out.print(currNode.value + "");
    }

    public boolean removeNode(int val) { //删除节点
        Node preNode = null;
        Node currNode = headNode;
        for (int i = 0; i < size; i++) { //遍历链表找节点
            if (currNode.value == val) { //找到处理
                if (currNode.pre == null) { //头节点
                    headNode = currNode.curr;
                    size--;
                    return true;
                } else if (currNode.curr == null) { //尾节点
                    currNode.pre.curr = null;
                    size--;
                    return true;
                } else { //其他情况
                    preNode.curr = currNode.curr;
                    currNode.curr.pre = preNode;
                    size--;
                    return true;
                }
            }
            preNode = currNode;
            currNode = currNode.curr;
        }
        return false;
    }
}

手搓链表

全部评论

相关推荐

03-15 20:26
已编辑
电子科技大学 C++
T3题面:给一个3e5数组,每次询问长度为len的子数组乘积的和,如果子数组乘积&gt;1e9,则视为0.赛后一分钟想出来了,比赛时打了个暴力+线段树注意到1e9大约是2^30,&nbsp;因此len长度如果&gt;30就直接输出0,30以内做一个记忆化就行,复杂度O(30*n)感觉是以前比赛做过的题,忘了怎么做了。。。---upd:&nbsp;忘了数据范围了,如果有0,1的话那这样也不行
blueswiller:给出一个做法,刚刚才想到,应该没问题,时间复杂度为 O(max(30n, nlogn)): 1. 根据 0 切分数组。2. 现在问题转化为>=1 的情况,我们首先维护每一个数前一个 > 1 的数的位置,同时维护一个长度的差分数组,初始值全为 0。3. 我们从每一个数 i 开始向前跳,至多跳 30 次,维护这个过程中的乘积,于是得到 30 个区间加和。举例:假设从 j1 跳到 j2 ,相当于对查询长度 (i- j1 + 1) 至 (i - j2) 贡献 a_i * ... * a_j1。4. 对于所有区间加和,我们采用差分数组结合树状数组对其进行维护,由于长度至多为 n ,树状数组构建的复杂度为 O(nlogn),于是,构建阶段的复杂度为 O(max(30n, nlogn))。在线单次查询的复杂度为树状数组查询的复杂度 O(logn)。
投递淘天集团等公司10个岗位 > 笔试
点赞 评论 收藏
分享
03-07 17:32
已编辑
中南大学 C++
是只吗喽:淘天和米哈游之间只隔了15分钟,有点极限了xd
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客企业服务