java leetCode(链表类型题)

目录

7.整数反转

19. 删除链表的倒数第N个节点

20. 有效的括号

21:合并两个有序链表

23. 合并K个排序链表

61.旋转链表

148.排序链表

203.    移除链表中相同名称的元素

206. 反转链表

328 奇偶链表


 

 

7.整数反转

7.Reverse 整数反转

1.用 % 的方法得到整数的最后一个数字 ,此时再用给定的整数 / 去除最后一个数字

 如果整数还存在(不为0) 此时 重复之前的操作 将先前得到的数字*10 + 上最后一个数字

 public static int reverse(int x) {
        int ret=0;
        while(x!=0){
            int temp=ret*10+x%10;
            if(temp/10!=ret||Integer.MIN_VALUE>ret || ret>Integer.MAX_VALUE)  //temp/10 在java中
                // 内存超限了不会报错 数值会减小
                return 0;
            ret = temp;
            x=x/10;
        }

        return ret;
    }

也可以用转换字符串的方法 将整数转换为字符串后再次进行整数倒置

    public static int reverse(int x) {
        int k=0;
        String s= String.valueOf(x);
        Long judege=0L;
        String ss="";
        int ans=0;
        int length=s.length();
        if(s.charAt(0)=='-'){
            k=1;
            ss+="-";
        }
        for(int i=length-1;i>=k;i--){
            ss+=s.charAt(i);
        }
        judege=Long.parseLong(ss);
        if(Integer.MIN_VALUE<=judege && judege<=Integer.MAX_VALUE){
            return judege.intValue();
        }else {
            return 0;
        }
    }

 

19. 删除链表的倒数第N个节点

dummy 哑巴

加入哑结点 防止极端情况删除第一个结点时没有前驱结点 做单独判断

方法1.查询一次链表的长度后,再次遍历删除倒数第n个结点

方法2.将查询到的结点放入进数组(集合)中,第二次直接查询出要删除结点的前驱结点(size-n-1) size为链表的长度,n为倒数第n个节点,数组查询的时间复杂度为o(1)

 private ListNode removeNthFromEnd(ListNode head, int n) {
        if(head.next==null)
            return null;
        List<ListNode> list = new ArrayList<ListNode>();
        int i=0;
        ListNode listnode = head;
        while(listnode.next!=null){
            list.add(listnode);
            listnode=listnode.next;
        }
        list.add(listnode);  //因为判断的是listnode.next!=null 最后一个结点还有加入
        int l=list.size();
        if(list.size()==n){     //将结点放在数组时 删除最后一个元素时情况要做出特殊处理 因为l-n-1会越界
            head=head.next;
            return head;
        }
        ListNode node=list.get(l-n-1); //l-n-1到删除结点的上一个结点
        node.next=node.next.next;
        return head;
    }

方法3:比较巧妙,运用双指针l1,l2, 因为要删除倒数的结点,当l1指向链表的最后一个元素,此时l1-l2(index)索引位置为n

此时l2指向的元素就是需要删除元素的前驱结点 eg: a b c  , n=2(表示此时要删除的元素为b), l1指向a  ,l2指向c  ,c-a=2;

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
 public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy=new ListNode(0);
        dummy.next=head;
        ListNode l1=dummy;
        ListNode l2=dummy;
        int i=0,j=0;
        while(l1.next!=null){
            if(j-i<n){
                j++;
                l1=l1.next;
            }
            else {
                i++;
                l2=l2.next;
            }
        }
        l2.next=l2.next.next;
        return dummy.next;
    }
}

括号匹配

IsValid

20. 有效的括号

/**
 * 用栈去解决问题
 * 当遇到( [ { 时就入栈 当遇到右括号就出栈 并判断是否与栈值匹配
 * 最后判断栈中是否为空 因为会遇到(( 此种情况
 */
    public boolean isValid(String s) {
        int length=s.length();
        char []ch=new char[length];
        int top=0;
        char b ;
        if(length==0||s==null){
            return true;
        }

        for(int i=0;i<length;i++){
            char a=s.charAt(i);
            if(a=='('||a=='{'||a=='['){
                ch[top++]=s.charAt(i);
            }else if((a==')'||a==']'||a=='}')&&top==0){ //当队列为空 且括号为右括号时 直接返回
                return false;
            }
            else if(a==')'){
                b=ch[--top];
                if(b!='(') return false;
            }else if(a=='}'){
                b=ch[--top];
                if(b!='{') return false;
            }else if(a==']'){
                b=ch[--top];
                if(b!='[') return false;
            }
        }
        if(top!=0)
            return false;
        else
            return true;
    }

21:合并两个有序链表

  两个有序的数组或是链表进行合并 都可以用锯齿排序:

 

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode l3=new ListNode(-1); //建立链表时一般创建一个哑结点,就不用单独处理第一个结点了
        ListNode first = l3; //新创建一个引用操作链表,为了保存头节点
        while(l1!=null&&l2!=null){ //此处最好不要用l->next 因为最后一个元素还没有判断
            if(l1.val<l2.val)
            {
                first.next=new ListNode(l1.val);
                l1=l1.next;
                first=first.next;
            }
            else
            {
                first.next=new ListNode(l2.val);
                l2=l2.next;
                first=first.next;
            }   
        }
        while(l1!=null){
            first.next=new ListNode(l1.val);
            l1=l1.next;
            first=first.next;
        }
        while(l2!=null){
            first.next=new ListNode(l2.val);
            l2=l2.next;
            first=first.next;
        }
        return l3.next;
        
    }
}

23. 合并K个排序链表

用了分治算法,与21 合并两个有序链表 相像 但是直接用for循环调用合并函数会超时

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
     public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 
        ListNode l3=new ListNode(-1); //建立链表时一般创建一个哑结点,就不用单独处理第一个结点了
        ListNode first = l3; //新创建一个引用操作链表,为了保存头节点
        while(l1!=null&&l2!=null){ //此处最好不要用l->next 因为最后一个元素还没有判断
            if(l1.val<l2.val)
            {
                first.next=new ListNode(l1.val);
                l1=l1.next;
                first=first.next;
            }
            else
            {
                first.next=new ListNode(l2.val);
                l2=l2.next;
                first=first.next;
            }   
        }
        while(l1!=null){
            first.next=new ListNode(l1.val);
            l1=l1.next;
            first=first.next;
        }
        while(l2!=null){
            first.next=new ListNode(l2.val);
            l2=l2.next;
            first=first.next;
        }
        return l3.next;
        
    }
    public ListNode mergeSort(ListNode[] lists,int l,int r){ //分治排序
        if(l==r)
            return lists[l];
         else{
            int mid=(l+r)/2;
            ListNode leftNode = mergeSort(lists,l,mid);
            ListNode rightNode = mergeSort(lists,mid+1,r);
            return mergeTwoLists(leftNode,rightNode);
        }  
    }
    public ListNode mergeKLists(ListNode[] lists) {
        if(lists==null||lists.length==0){
            return null;
        }
        return mergeSort(lists,0,lists.length-1); //记住此种情况要判空
    }
}

61.旋转链表

/**
 * 61. 旋转链表  思路和删除链表倒数结点 相同 
   取快慢指针i,j
   使指针j-i相差n步
   然后使最后的结点与头结点相连,使dummy.next连向 (最后的结点为第一个移动的元素 pre->next表示需要被移动的)最后一个元素,
   after.next=head;
        dummy.next=pre.next;
        pre.next=null;
       

 */
 public ListNode rotateRight(ListNode head, int k) {
        ListNode dummy = new ListNode(-1);
        int length=0;
        ListNode pre=dummy,after=dummy,first=dummy; //因为设定了哑结点 所以不用判断空
        int i=0,j=0;
        dummy.next=head;
        while(first.next!=null){
            first=first.next;
            length++;
        }
        while(after.next!=null){
            if(j-i<(k%length)){
                j++;
                after=after.next;
            }else{
                i++;
                pre=pre.next;
            }
        }
        after.next=head;
        dummy.next=pre.next;
        pre.next=null;
        return dummy.next;

    }

148.排序链表

一开始的思路 将链表放入数组中,进行分治算法的实现

 

 改进后的思路  直接在链表上使用分治算法 ,只不过链表的分治算法

设定快慢指针,快指针一次走两个,慢指针一次走一个,最终能将链表分成相等的两段
/**
     * 直接用链表进行分治排序
     * 设定快慢指针,快指针一次走两个,慢指针一次走一个,最终能将链表分成相等的两段
     * @param head
     * @return
     */
    public ListNode sortList(ListNode head) {
        if(head==null){
            return head;
        }else{
            return mergeSort(head);
        }
    }
    public ListNode mergeSort(ListNode head){

        if(head.next==null){ //递归返回条件 如果只有1个点就返回
            return head;
        }

        ListNode pre=head;
        ListNode after=head;
        ListNode temp=null;
        while(after!=null && after.next!=null){// 如果判断条件是after.next.next!=null 此时如果链表中只有三个点 temp会指向空指针
            temp=pre;
            pre=pre.next;
            after=after.next.next;
        }
        temp.next=null;
        ListNode l = mergeSort(head);
        ListNode r = mergeSort(pre);
        return merge(l,r);

    }
    public ListNode merge(ListNode l,ListNode r){
        ListNode dummpy=new ListNode(-1);
        ListNode first = dummpy;
        while(l!=null && r!=null){
            if(l.val<=r.val){
                first.next=l;
                first=first.next;
                l=l.next;
            }else{
                first.next=r;
                first=first.next;
                r=r.next;
            }
        }
        if(l!=null){
            first.next=l;
        }
        if(r!=null){
            first.next=r;
        }
        return dummpy.next;
    }

203.    移除链表中相同名称的元素

   public ListNode removeElements(ListNode head, int val) {
        ListNode dummy=new ListNode(-1);
        dummy.next=head;
        ListNode first = dummy;
        //思维导图 判断了结点相同 first是没有移动的 结点不同再移动指针
        while(first.next!=null){
            if(first.next.val!=val){
                first=first.next;
            }else{
                first.next=first.next.next;
            }
        }
        return dummy.next;

    }

206. 反转链表

   此题用1.递归的思想将链表倒转,先将链表遍历然后链表的指针倒置,使末尾结点变为首结点(同时作为返回条件),

 

未改良版递归(需要从末尾的结点将每一个数都遍历一次,再插入结点)(时间复杂度空间复杂度很高)实现:

    public ListNode reverseList(ListNode head) {
        ListNode l2 = new ListNode(0);
        if(head==null) return null;
        if(head.next==null){
            l2=head;
            return l2;
        }else{
            l2=reverseList(head.next);
            ListNode first=l2;
            while(first.next!=null){
                first=first.next;
            }
            first.next=new ListNode(head.val);     //递归时此处要注意 不能使first.next与此时递归的结点相同 因为结点并不包含一个值,而是多个值
            return l2;
        }
    }

 

         

           

改进后的递归: 只改变指针方向就行

    
class Solution {
    //递归 将链表的指向倒转 最后返回最后一个结点
    public ListNode reverseList(ListNode head) {
        ListNode l2 = new ListNode(0);
        if(head==null||head.next==null){
            return head;
        }else{
            l2=reverseList(head.next);
            head.next.next=head;         //将指针反转
            head.next=null;              //同时将正向的指针清除,防止形成循环
            return l2;
        }
         
    }
}

             2.迭代:

       与递归(从最后更改链表指针的方向)相反,迭代是在遍历的时候就开始更改指针指向的方向

    
class Solution {
    //迭代 将链表的指向倒转 最后返回最后一个结点
    public ListNode reverseList(ListNode head) {
         if(head==null||head.next==null){ // //所谓的空指针,就是指你的引用指向了没有分配内容的内
           //这个时候就会报空指针异常,
            return head;
        }
        ListNode pre = head;
        ListNode after = head.next; //要做空指针判定
        ListNode temp=null;
        head.next=null;       //已经保存了第一个和第二个结点,此时只需要将第二个结点的next连到第一//就行,然后 1结点到二结点的边断掉 不然会形成循环
       while(after!=null){
           temp=after.next;
           after.next=pre;
           // pre.next=null; 这个代码不能加 因为这个会断了之前after已经倒置的指针
           pre=after;
           after=temp;
       }
       return pre;
    }
}

 

 

328 奇偶链表

/**
 * 328. 奇偶链表

方法一:
 * 给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。
 * 请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
 * 思路
 * 定义变量 i 判断奇偶性
 *          将偶数部分放到链表l1,偶数部分放到链表l2
 *          然后l1的尾部连到l2的首部
 *          最后返回l1的首部
 */

     
  public ListNode oddEvenList(ListNode head) {
        ListNode dummy = new ListNode(-1);
        ListNode l1    = new ListNode(-1);
        ListNode l2    = new ListNode(-1);
        dummy.next=head;
        ListNode first = dummy,first1=l1,first2=l2;
        int i=0;
        while(first.next!=null){
            if(i%2==0){
                i++;
                first=first.next;
                first1.next=new ListNode(first.val);
                first1=first1.next;
            }else{
                i++;
                first=first.next;
                first2.next=new ListNode(first.val);
                first2=first2.next;
            }
        }
        first1.next=l2.next;         //这里不要连错了 是l1的最后一个结点与l2的首结点相连
        return l1.next;

    }

方法2

但此题要求空间复杂度为1 因此直接在链表上进行奇偶结点的置换 关键要进行非空判断

改良版 直接在原链表进行奇偶结点交换
    public ListNode oddEvenList(ListNode head) {
        if(head==null || head.next==null)
            return head;
        // head 为奇链表头结点,o 为奇链表尾节点
        ListNode o = head;
        // p 为偶链表头结点
        ListNode p = head.next;
        // e 为偶链表尾节点
        ListNode e = head.next;
        while(  e.next!=null&&o.next!=null ){
            o.next=e.next;
            o=o.next;
            e.next=o.next;
            e=e.next;
            if(o.next==null)
                break;
        }

        o.next=p;
        return head;
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值