剑指Offer 21-22

254 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情

21、调整数组顺序使奇数位于偶数前面

输入一个整数数组,要求实现一个函数调整该数组中数字的顺序,使得数组的所有奇数在前半部分,数组的所有偶数在后半部分。

解题思路

我们可以使用双指针来解决本题,从前往后遍历数组,每次都判断属于奇数还是偶数,如果是奇数则从新的数组的前面开始插入,否则从新的数组的后面进行插入。最终返回新的数组即可,代码如下:

public int[] exchange(int[] nums) {
    int len = nums.length;
    int[] res = new int[len];
    int left = 0;
    int right = len - 1;
    for(int i=0;i<len;i++){
        if(nums[i] % 2 == 1){
            res[left++] = nums[i];
        }else {
            res[right--] = nums[i];
        }
    }
    return res;
}

上面的时间复杂度和空间复杂度都是O(n)O(n),实际上空间可以进一步优化,优化思路如下:

可以从前往后找到第一个偶数和从后往前找到第一个奇数,之后交换位置即可,这样当left和right相遇时即数组遍历完毕,代码如下:

public int[] exchange(int[] nums) {
    int len = nums.length;
    int left = 0;
    int right = len - 1;
    while(left<right){
        while(left<right&&nums[left]%2!=0) left++;
        while(left<right&&nums[right]%2!=1) right--;
        int temp = nums[left];
        nums[left] = nums[right];
        nums[right] = temp;
    }
    return nums;
}

此时空间复杂度就为O(1)O(1)

22、链表中倒数第k个节点

给定一个链表,要求输出该链表的倒数第k个节点。

解题思路

简单的思路,首先计算链表的长度,之后再次遍历链表,返回链表的第lenk+1len-k+1个节点即可,代码如下:

public ListNode getKthFromEnd(ListNode head, int k) {
    int len = 0;
    ListNode cur = head;
    while(cur!=null){
        len ++;
        cur = cur.next;
    }
    int curLen = 0;
    while(head!=null){
        if(curLen==len-k+1){
            return head;
        }
        curLen++;
        head = head.next;
    }
    return null;
}

时间复杂度O(n)O(n)。另外一种更简单的思路是使用快慢指针,我们可以让快指针先走k步,之后慢指针再和快指针一起走,最终返回慢指针即可:

public ListNode getKthFromEnd(ListNode head, int k) {
    ListNode fast = head;
    ListNode slow = head;
    for(int i=0;i<k;i++){
        fast = fast.next;
    }
    while(fast!=null){
        fast = fast.next;
        slow = slow.next;
    }
    return slow;
}