剑指offer-day02链表

1.从尾到头打印链表

解法1:栈

解题思路:

  1. 将节点元素压入栈中
  2. 将栈中元素弹出,依次放入数组,返回数组
class Solution {
    public int[] reversePrint(ListNode head) {
       Stack<ListNode> stack=new Stack<>();
        while (head!=null){
            stack.push(head);
            head=head.next;
        }
        int[] array=new int[stack.size()];
        for (int i = 0; i < array.length; i++) {
            array[i]=stack.pop().val;
        }
        return array;
    }
}

解法2:反转链表

解题思路:

  1. 用链表反转函数将链表反转
  2. 遍历新的链表,将链表的值依次放入数组
  3. 还原链表,返回数组

链表反转函数:

public ListNode reverseList(ListNode head) {
        ListNode cur=head;
        ListNode pre=null;
        while (cur!=null){
            head=head.next;
            cur.next=pre;
            pre=cur;
            cur=head;
        }
        return pre;
    }

主函数:
ps:这函数一点都不好,下一个。

 public int[] reversePrint1(ListNode head) {
        head = reverseList(head);
        ListNode cur=head;
        ArrayList<Integer> list=new ArrayList<>();
        while (cur!=null){
            list.add(cur.val);
            cur=cur.next;
        }
        int[] array=new int[list.size()];
        int i=0;
        while (!list.isEmpty()){
            array[i++]=list.remove(i);
            i++;
        }
        head=reverseList(head);
        return array;
    }

解法3:遍历大法

解题思路:

  1. 第一遍遍历找出链表长度,第二遍遍历直接给数组赋值
  2. 返回数组
public static int[] reversePrint(ListNode head) {
        ListNode node = head;
        int count = 0;
        while (node != null) {
            ++count;
            node = node.next;
        }
        int[] nums = new int[count];
        node = head;
        for (int i = count - 1; i >= 0; --i) {
            nums[i] = node.val;
            node = node.next;
        }
        return nums;
 }

2.链表反转

解法1:栈

解题思路:

  1. 利用栈的特性,压栈,弹栈,很简单
public ListNode reverseList_stack(ListNode head) {
        if (head == null) return head;
        Stack<ListNode> stack = new Stack<>();
        while (head!=null){
            stack.push(head);
            head = head.next;
        }
        ListNode newHead = stack.pop();
        ListNode tailNode = newHead;
        while (!stack.isEmpty()){
            ListNode cur =  stack.pop();
            tailNode.next = cur;
            tailNode = cur;
        }
        tailNode.next = null;
        return newHead;
    }

解法2:头插法

解题思路:
while循环
头节点下移,
cur节点的next指pre节点,
pre节点下移,
cur节点找到头节点head

 public ListNode reverseList(ListNode head) {
        ListNode cur=head;
        ListNode pre=null;
        while (cur!=null){
            head=head.next;
            cur.next=pre;
            pre=cur;
            cur=head;
        }
        return pre;
    }

解法3:递归
递归与方法1原理相似,利用系统栈,实现链表反转

3.复杂链表的复制

解法1:HashMap
思路:

  1. 若头节点 head 为空节点,直接返回null ;
  2. 初始化: 哈希表 map, 节点 cur 指向头节点;
  3. 复制链表:
    建立新节点,并向 map添加键值对 (原 cur 节点, 新 cur 节点) ;
    cur 遍历至原链表下一节点;
  4. 构建新链表的引用指向:
    构建新节点的 next 和 random 引用指向;
  5. cur 遍历至原链表下一节点;
    返回值: 新链表的头节点 map[head] ;
		HashMap<Node,Node> nextMap=new HashMap<>();
        Node cur=head;
        while (cur!=null){
            nextMap.put(cur, new Node(cur.val));
            cur=cur.next;
        }
        cur=head;
        while (cur!=null){
            nextMap.get(cur).next=nextMap.get(cur.next);
            nextMap.get(cur).random=nextMap.get(cur.random);
            cur=cur.next;
        }
        return nextMap.get(head);

解法2:相对位置克隆

解法:

  1. 克隆原节点
  2. 对照相对位置,克隆random
  3. 将链表拆分,得到新链表

n1->n1’->n2->n2’->null

public Node copyRandomList(Node head) {
        if(head == null) return null;
        Node cur = head;
        // 1. 复制各节点,并构建拼接链表
        while(cur != null) {
            Node tmp = new Node(cur.val);
            tmp.next = cur.next;
            cur.next = tmp;
            cur = tmp.next;
        }
        // 2. 构建各新节点的 random 指向
        cur = head;
        while(cur != null) {
            if(cur.random != null)
                cur.next.random = cur.random.next;
            cur = cur.next.next;
        }
        // 3. 拆分两链表
        cur = head.next;
        Node pre = head, res = head.next;
        while(cur.next != null) {
            pre.next = pre.next.next;
            cur.next = cur.next.next;
            pre = pre.next;
            cur = cur.next;
        }
        pre.next = null; // 单独处理原链表尾节点
        return res; 

    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值