Java算法问题学习笔记(三)(数组分排、链表倒数K节点、链表反转、递增链表合并问题)

一、数组奇偶分排问题

Q:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

A:分析:若不需要保证奇数和偶数调整后的分别相对顺序,则可使用双指针头尾相向扫描,判断奇偶性后调整位置即可;但若要考虑调整后的相对位置不变,则需要创建新的数组作为中介为妥。及将参数数组复制作为标的,统计数组奇数个数作为奇偶数分界点。再次遍历数组,分别以数组起始点与奇数统计总数点为排序后数组的奇数和偶数的占位起始点,依次进行奇偶判断元素替换,对应索引值步进一位即可。

代码如下:

public void reOrderArray(int[] array){
        int[] arrayClone=array.clone();
        int oddCount=0;
        for(int i=0;i<array.length;i++){
            if(array[i]%2==1)
                oddCount++;//统计奇数个数
        }
        int oddPointer=0,evenPointer=oddCount;
        for(int j=0;j<arrayClone.length;j++){
            if(arrayClone[j]%2==1)
                array[oddPointer++]=arrayClone[j];//奇数按顺序占位
            if(arrayClone[j]%2==0)
                array[evenPointer++]=arrayClone[j];//偶数按顺序占位
        }
    }

二、链表倒数K节点问题

Q:输入一个链表,输出该链表中倒数第k个结点。

A:分析:该问题有两种解决方案:1.构建两个指针节点指向链表头结点p,q,p开始遍历直到链表结束,当p至第k个节点时,q开始遍历,使得p,q之间间隔始终保持为k,从而p至终点时,q指向倒数第k个节点。2.遍历两次链表,第一次确定链表长度,第二次直接遍历到length-k即可。

第一种方案代码如下:

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

        ListNode(int val) {
            this.val = val;
        }
    }
    public ListNode FindKthToTail(ListNode head,int k) {
        if(head==null||k<0)
            return null;//若链表为空或k不符合条件
        ListNode p=head,q=head;
        int i=0;
        for(;p!=null;i++){
            if(i>=k)
                q=q.next;//当p遍历到第k个节点后,q开始遍历,从而保证p,q之间的间隔始终为k
            p=p.next;//p一直遍历到链表终点
        }
        if(i<k)//若链表长度小于k,错误
            return null;
        return q;
    }

三、链表反转问题

Q:输入一个链表,反转链表后,输出新链表的表头。

A:分析:由于给定链表为单链表,因此,要将单链表反转,就必须将原有的链表节点连接打断,重新建立反转后的链表结构。

具体思路为:构建preNode,curNode,nextNode分别作为节点的前序节点、当前节点、后续节点,按正常链表顺序进行节点遍历。以起始点为例,其前序节点为null,当前节点在链表反转后则变为链表的尾结点,当前节点的后续节点则成为反转后的前序节点。节点移动后同步更新preNode,curNode,nextNode。

代码如下:

public ListNode ReverseList(ListNode head) {
        ListNode preNode=null,nextNode=null,curNode=head;
        if(head==null||head.next==null)
            return head;
        while(curNode!=null){
            nextNode=curNode.next;//后续节点
            curNode.next=preNode;//反转节点后的next设置为前一个节点
            preNode=curNode;//当前节点变为前序节点
            curNode=nextNode;//当前节点后移
        }
        return preNode;
    }

四、递增链表合并问题

Q:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

A:分析:由链表的单调递增特性可知,链表的节点合并只需要分别对比两个链表当前节点的大小,取最小值后将对应链表节点步进一位即可实现合并后的链表仍满足递增特性。由于每一次链表节点判断方式存在同质性,故使用递归方式即可解决该问题。

代码如下:

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

        ListNode(int val) {
            this.val = val;
        }
    }

    public ListNode Merge(ListNode list1,ListNode list2) {
        ListNode mergeNode=null;
        if(list1==null)
            return list2;//链表为空,直接返回另一个链表
        if(list2==null)
            return list1;
        if(list1.val<list2.val){//取较小值赋予合并后链表的当前节点
            mergeNode=list1;
            mergeNode.next=Merge(list1.next,list2);//递归赋值
        }else {
            mergeNode=list2;
            mergeNode.next=Merge(list1,list2.next);
        }
        return mergeNode;
    }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值