数据结构——leetcode(链表练习)[java]

leetcode-19-删除链表的倒数第 n 个节点

力扣-19
题目:给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点
示例
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
思路:遍历两遍,第一遍找到链表长度,第二遍遍历到被删除结点的前一个位置,删除结点。

/**
public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
 public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode first =head;
        ListNode dummy=new ListNode(0);//设置哑巴结点
        dummy.next=head;
        int count=0;//计数器
        while(first!=null){
            count++;
            first=first.next;

        }
        first=dummy;//防止first结点改变,引入dummy哑巴结点
        count-=n;
        while(count>0){
            count--;
            first=first.next;
        }
        first.next=first.next.next;
        return dummy.next;


    }

leetcode-24-交换链表中的相邻结点

力扣-24
题目:给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例
给定 1->2->3->4, 你应该返回 2->1->4->3.
思路:递归思路,交换两两结点,head开始遍历,依次遍历firstNode,SecondNode,下一次递归则是传递的是下一对需要交换的节点。若链表中还有节点,则继续递归,直到head.next为空。
看到一个比较好的讲述递归的博客三道题套路解决递归问题.

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head==null||head.next==null){
            return head;
        }
        ListNode firstNode = head;
        ListNode SecondNode = head.next;
        firstNode.next=swapPairs(SecondNode.next);
        SecondNode.next=firstNode;
        return SecondNode;

    }
}

leetcode-206-链表反转

力扣-206
题目:你可以迭代或递归地反转链表
示例
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
思路
双指针迭代【头插法】(链表逆序需要运用头插法)
在这里插入图片描述
双指针迭代

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while(cur!=null){
            ListNode temp =cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;

    }
}

leetcode-445-两数相加Ⅱ(链表求和)

力扣-445
题目:不能修改原始链表
示例
输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 8 -> 0 -> 7
思路:遇到逆序输出时,首先想到栈,两个链表压入两个栈中,取出后,头插法插入。链表逆序需要运用头插法(leetcode206的链表反转)上面也有链表反转的解析~

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Stack<Integer> stack1 = new Stack<>();
        Stack<Integer> stack2 = new Stack<>();
        while(l1!=null){
            stack1.push(l1.val);
            l1 = l1.next;
        }
        while(l2!=null){
            stack2.push(l2.val);
            l2 = l2.next;
        }
        //记录进位
        int carry = 0;
        ListNode head = null;
        while(!stack1.isEmpty()||!stack2.isEmpty()||carry>0){
            int sum = carry;
            sum+=stack1.isEmpty()?0:stack1.pop();
            sum+=stack2.isEmpty()?0:stack2.pop();
            ListNode node = new ListNode(sum%10);
            node.next = head;
            head = node;
             //carry 0 or 1
            carry = sum /10;
        }
            return head;
    }
}

leetcode-234-回文链表

力扣-234
题目:请判断一个链表是否为回文链表,以 O(1) 的空间复杂度来求解
示例
输入: 1->2
输出: false

输入: 1->2->2->1
输出: true
思路
1.链表中的数值存入数组,利用数组双向指针检查
2.快慢指针遍历链表,将后半段链表反转,再比较,讲链表恢复。
1.辅助数组法

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isPalindrome(ListNode head) {
        ArrayList<Integer> list = new ArrayList();
        if(head==null||head.next==null){
            return true;
        }
        ListNode cur = head;
        while(cur!=null){
            list.add(cur.val);
            cur= cur.next;
        }
        //头指针
        int he=0;
        //尾指针
        int la=list.size()-1;
        while(he<=la){
            if(!list.get(he).equals(list.get(la))){
                return false;
            }
            he++;
            la--;
        }
        return true;
    }
}

2.快慢指针反转链表法 设置快慢指针遍历链表,快慢指针遍历时,利用头插法将前半部分链表反转,之后比较前半部分和后半部分链表各个结点的值
注意:链表的结点是奇数还是偶数

class Solution {
    public boolean isPalindrome(ListNode head) {
     if(head==null||head.next==null){
         return true;
     }
     ListNode slow = head;//慢指针
     ListNode fast = head;//快指针
     ListNode pre = null;//相当于dummynode,head前面的结点
     while(fast!=null&&fast.next!=null){
         ListNode cur = slow;
         slow = slow.next;
         fast = fast.next.next;
         cur.next = pre;
         pre=cur;
     }
     //链表结点为奇数时
     if(fast!=null){
         slow=slow.next;
     }
     //两个半长链表的比较
     while(pre!=null){
            if (pre.val != slow.val)
            return false;
            slow = slow.next;
            pre = pre.next;
        }
       return true;
    }     
}

leetcode-725-分割链表

力扣-725
题目
把链表分隔成 k 部分,每部分的长度都应该尽可能相同,排在前面的长度应该大于等于后面的。
示例
输入:
root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
输出: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
解释:
输入被分成了几个连续的部分,并且每部分的长度相差不超过1.前面部分的长度大于等于后面部分的长度。

思路:截断链表

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode[] splitListToParts(ListNode root, int k) {
       //获取链表长度
       ListNode p =root;
       int count=0;
       while(p!=null){
           count++;
           p=p.next;
       }
       p=root;
       ListNode [] res=new ListNode[k];
       //k>总长度,取每一个链表结点
       if(k>=count){
           for(int i= 0;i<count;i++){
               res[i]= new ListNode(p.val);
               p=p.next;
           }
       }else{//k<总长度
       int remain = count % k;
       int preCount = count/k;
       //记录每部分需要存储的链表元素
       int [] counts = new int[k];
       for(int i=0;i<k;i++){
           counts[i]=remain-->0?preCount+1:preCount;   
       }
       //遍历链表,存储元素
       for(int i=0;i<k;i++){
           //获取当前部分需要的元素个数
           int num = counts[i];
           res[i]=p;
           //调整p的位置
           while(--num>0){
               p=p.next;
           }
           //截断链表
           ListNode temp = p.next;
           p.next = null;
           p=temp;
       }

       }
           return res; 
    }
}

//2
public ListNode[] splitListToParts(ListNode root, int k) {
    int N = 0;
    ListNode cur = root;
    while (cur != null) {
        N++;
        cur = cur.next;
    }
    int mod = N % k;
    int size = N / k;
    ListNode[] ret = new ListNode[k];
    cur = root;
    for (int i = 0; cur != null && i < k; i++) {
        ret[i] = cur;
        int curSize = size + (mod-- > 0 ? 1 : 0);
        for (int j = 0; j < curSize - 1; j++) {
            cur = cur.next;
        }
        ListNode next = cur.next;
        cur.next = null;
        cur = next;
    }
    return ret;
}

leetcode-328-链表元素按奇偶聚集

力扣-328
题目
给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。
请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
示例
输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL
思路
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode oddEvenList(ListNode head) {
        if(head ==null||head.next==null){
            return head;
        }
        //链表奇数结点 head 奇链表头 o奇链表尾 
        ListNode o = head;
        //链表偶数结点 p 偶链表头 e 偶链表尾 
        ListNode p = head.next;
        ListNode e = p;
        while(o.next!=null&&e.next!=null){
            o.next = e.next;
            o = o.next;
            e.next = o.next;
            e = e.next;
        }
        o.next = p;
        return head;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值