【数据结构-Java描述】顺序表与链表OJ题

杨辉三角

OJ链接:杨辉三角

思路:每一行的第一列和最后一列都是1,其余列是都是上一行的j和j-1的和,我们实例化一个二维顺序表,遍历这个杨辉三角,往顺序表内存入即可。

代码:

public static List> generate(int numRows) {
        List> ret= new ArrayList<>();
        for(int i=0;i list=new ArrayList<>();
            for(int j=0;j<=i;j++){
                if(j==0 || j==i){list.add(1);}
                else if(i>1){
                    list.add(ret.get(i-1).get(j-1)+ret.get(i-1).get(j));
                }
            }
            ret.add(list);
        }
        return ret;
    }

原地移除数组中所有的元素val,要求时间复杂度为O(N),空间复杂度为O(1) 

 OJ链接:数组移除元素

思路:题目说明了元素的顺序可以改变。不需要考虑数组中超出新长度后面的元素。,

所以每出现一个和val相同的元素,我们就拿他和数组最后的元素替换,要注意的是,每替换一次,数组的长度要减小。

代码:
 

public int removeElement(int[] nums, int val) {
        int flag = 0;
        for(int i=0;i

删除排序数组中的重复项

  OJ链接:数组移除元素 ​

思路:由于数组已经升序,所以重复项会出现在一起,我们找到重复项后面的数组整体前移,从而将重复项覆盖,每次移动要记录下覆盖的重复项个数,然后返回新的数组长度。

代码:

class Solution {
    public int removeDuplicates(int[] nums) {
        int flag = 0;
        for(int i = 0; i < nums.length - flag; i++) {
            int j = i + 1;
            while (j < nums.length - flag && nums[j] == nums[i]) {
                j++;
            }
            flag += j - i - 1;
            if (j > i + 1) {
                for (int k = 0; j + k < nums.length; k++) {
                    nums[i + 1 + k] = nums[j + k];
                }
            }
        }
        return nums.length-flag;
    }
}

合并两个有序数组

OJ链接:合并两个有序数组

思路:数组已经有序,所以我们遍历第二个数组,遍历时把比数组1第一个元素小的元素全部放到左边,数组1整体右移,之后从数组2中取得元素,在数组1中找到合适位置放入即可,放入时,数组1插入位置后的元素整体右移。

代码:

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
       int j=0;
       int flag=0;
       for(int i=0;i=nums2[i]){
               for(int k = 0;m+flag-1-k>=j; k++){
                   nums1[m+flag-k] = nums1[m+flag-1-k];
               }
               nums1[j]=nums2[i];
               flag++;
           }else{
               while(jnums1[j]){
                   j++;
               }
               for(int k = 0;m+flag-1-k>=j; k++){
                   nums1[m+flag-k] = nums1[m+flag-1-k];
               }
               nums1[j]=nums2[i];
               flag++;
           }
       }
   }
}

 删除链表中所有值为value的元素

 OJ链接: 删除链表中所有值为value的元素

思路:遍历链表,遍历时记录当前节点与当前节点的前驱节点,删除节点-将前驱节点指向后继节点即可,如果是头结点,直接将新的头结点指向后继节点即可。

代码:

public ListNode removeElements(ListNode head, int val) {
        ListNode cur=head;
        ListNode prev=null;
        while(cur!=null){
            if(cur.val==val) {
                if(prev==null){
                    head=head.next;
                    prev=null;
                }else{
                    prev.next=cur.next;
                }
                cur=cur.next;
                continue;
            }
            prev=cur;
            cur=cur.next;
        }
        return head;
    }

单链表的逆置

 OJ链接:单链表的逆置

思路:链表逆置,从头遍历,设定一个前驱节点,开始时将前驱节点置为null,而后遍历时记录当前节点cur,后继节点curnext,前驱节点prev,逆置时,要先记录curnext,然后将当前节点的后继指向前驱prev,在把prev指向当前节点,然后把cur指向后继节点curnext.....最后返回尾部节点即可。

代码:

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head==null) return null;
       ListNode cur=head;
       ListNode prev=null;
       ListNode next=head;
       while(cur!=null)
       {
            next=cur.next;
            cur.next=prev;
            prev=cur;
            cur=next;
       }
       return prev;
    }

获取链表的中间节点

 OJ链接:获取链表的中间节点

思路:定义两个快慢指针,慢指针一次走一步,快指针走两步。当快指针走到尾部时,慢指针指向的即为中间节点,需要注意循环的终止判断语句。

代码:

public ListNode middleNode(ListNode head) {
        ListNode fast=head;
        ListNode slow=head;
      while(fast!=null && fast.next!=null){
             fast=fast.next.next;
             slow=slow.next;
      }
      return slow;
    }

获取链表倒数第K个节点

 OJ链接:获取链表倒数第K个节点

思路:与快慢指针类似。设定两个指针,让快指针先走k步,使得快慢指针相差K步,从而使得当快指针走到尾部时,慢指针指向倒数第k个节点,这里要注意判断K的合法性。

代码:

public ListNode FindKthToTail(ListNode  head,int k) {
        if(head==null || k<=0) return null;
        ListNode fast=head;
        ListNode slow=head;
        int flag=1;
        while(fast.next!=null){
            fast=fast.next;
            if(flag>=k) slow=slow.next;
            flag++;
        }
        if(flag

判断链表带环

 OJ链接:判断链表带环

思路:如果链表带环,则设定两个快慢指针,当快指针的步长为2,慢指针步长为1,如果带环,一定可以相遇,如果出现尾结点,那么一定不带环。

代码:

 public boolean hasCycle(ListNode head) {
        ListNode fast=head;
        ListNode slow=head;
        while(fast!=null && fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            if(fast==slow) return true;
        }
        return false;
    }

求环的入口点

  OJ链接:求环的入口点

思路:

【数据结构-Java描述】顺序表与链表OJ题_第1张图片

 

我们设置快慢两个指针,fast, slow ,fast一次前进两步,slow一次前进一步,设a为第一个节点到入环节点的距离。 a=[0->x],设b为入环口到相遇点的距离。b=[x->L],设c为相遇点到入环口的距离。c=[L->x]当fast,和slow相遇的时候,fast经过的节点是slow的两倍,设slow经过的节点数为S
根据上面的设置 可知 S=a+b ,2S=a+b+c+b,可知 a=c,此时让slow回到第一个节点,fast处于第一次相遇的节点,此时slow从第一个节点出发,各走一步,因为a=c,所以fast,和slow会在入环口第二次相遇,得到要求的节点。 

代码:

public ListNode detectCycle(ListNode head) {
        ListNode fast=head;
        ListNode slow=head;
        while(fast!=null && fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            if(fast==slow){
                fast=head;
                while(true){
                if(fast==slow) return fast;
                fast=fast.next;
                slow=slow.next;
                    }
            }
        }
        
        return null;
    }

判定链表相交

 OJ链接:判定链表相交

同时遍历两个链表,求出两个链表长度,让更长的链表先走长度的差值步,然后在同时走,同时走的时候判断两个节点是否相同,如果相同返回true;

代码:

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int sizea=0;
        int sizeb=0;
        ListNode cur1=headA;
        ListNode cur2=headB;
        while(cur1!=null || cur2!=null){
            if(cur1!=null){
              sizea++;
              cur1=cur1.next;
            }
            if(cur2!=null){
              sizeb++;
              cur2=cur2.next;
            }
        }
        cur1=headA;
        cur2=headB;
        while(sizea>sizeb){
            cur1=cur1.next;
            sizea--;
        }
        while(sizeb>sizea){
            cur2=cur2.next;
            sizeb--;
        }
        while(cur1!=null && cur2!=null){
            if(cur1==cur2) return cur1;
            cur1=cur1.next;
            cur2=cur2.next;
        }
        return null;
    
    }public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int sizea=0;
        int sizeb=0;
        ListNode cur1=headA;
        ListNode cur2=headB;
        while(cur1!=null || cur2!=null){
            if(cur1!=null){
              sizea++;
              cur1=cur1.next;
            }
            if(cur2!=null){
              sizeb++;
              cur2=cur2.next;
            }
        }
        cur1=headA;
        cur2=headB;
        while(sizea>sizeb){
            cur1=cur1.next;
            sizea--;
        }
        while(sizeb>sizea){
            cur2=cur2.next;
            sizeb--;
        }
        while(cur1!=null && cur2!=null){
            if(cur1==cur2) return cur1;
            cur1=cur1.next;
            cur2=cur2.next;
        }
        return null;
    
    }

判定链表是否是回文

  OJ链接:判定链表是否是回文

思路:设定快慢指针,将前半个链表逆置(如何逆置见上),然后从中间向两边遍历,判断两个节点的val值是否相同,如果不同返回false;如果两个链表都走完了也没有出现不同,返回true;

代码:

public boolean chkPalindrome(ListNode A) {
        ListNode fast=A;
        ListNode slow=A;
        ListNode prev=null;
        while(fast!=null && fast.next!=null){
            fast=fast.next.next;
            ListNode slownext=slow.next;
            slow.next=prev;
            prev=slow;
            slow=slownext;
        }
        while(prev!=null && slow!=null){
            if(prev.val!=slow.val) return false;
            prev=prev.next;
            slow=slow.next;
        }
        if(prev==null && slow==null) return true;
        return false;
    }

给定 x, 把一个链表整理成前半部分小于 x, 后半部分大于等于 x 的形式

 OJ链接:给定 x, 把一个链表整理成前半部分小于 x, 后半部分大于等于 x 的形式

思路:找到第一个小于x的节点,然后把之后小于x的节点接到第一个之后,最后把这一串接到头结点上。

代码;

import java.util.*;

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Partition {
    public ListNode partition(ListNode pHead, int x) {
        ListNode cur=pHead;
        ListNode prev=null;
        ListNode frist=null;
        while(cur!=null){
            if(cur.val

合并两个有序链表

 OJ链接:合并两个有序链表

思路:先把第二个链表中,比第一个链表头结点小的全部移到第一个链表头结点之前,然后更新头结点,之后遍历第二个链表剩下的节点,在第一个链表中找到合适位置插入。

代码:

public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode cur1=list1;
        ListNode cur2=list2;
        ListNode prev=null;
        if(list1==null) return list2;
        while(cur2!=null && cur2.val<=cur1.val){
            ListNode cur2next=cur2.next;
                cur2.next=cur1;
                list1=cur2;
                cur1=list1;
                cur2=cur2next;
        }
        while(cur2!=null){
             while(cur1!=null && cur2.val>cur1.val){
                    prev=cur1;
                    cur1=cur1.next;
                }
                ListNode cur2next=cur2.next;
                prev.next=cur2;
                cur2.next=cur1;
                prev=cur2;
                cur2=cur2next;
        }
        return list1;
    }

你可能感兴趣的:(笔记,java,数据结构,链表)