剑指offer编程Java实现pdf——持续更新中...

本文基于《剑指Offer》编程题的Java实现,涵盖多种算法问题,包括链表操作、数组处理、二叉树问题等,并对部分算法进行了优化。涉及题目有:数值的整数次方、O(1)时间删除链表节点、调整数组顺序、倒数第k个链表节点、反转链表、合并排序链表、二叉树镜像、最小的k个数等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

声明:本文参照——剑指Offer——编程题的Java实现,并对一些算法进行优化,以下简称《参考》。

面试题11:数值的整数次方

题目大致为:
    实现函数double power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
思路:
    可以考虑对指数折半,这样只需要计算一半的值,若指数是奇数,则-1再折半,否则直接折半。
   【注意】《参考》中未考虑指数为负数的情况。
Java实现
public class MainTest {

    public static void main(String[] args) {
        int base = 3;
        int exponent = -3;
        System.out.println(power(base, exponent));
        exponent = 6;
        System.out.println(power(base, exponent));
    }
    public static double power(double base, int exponent) {
        if (exponent == 0) return 1;
        if (exponent < 0) return 1 / power(base, -exponent);
        if (exponent % 2 == 0) {
            double temp = power(base, exponent >> 1);
            return temp * temp;
        } else {
            double temp = power(base, (exponent - 1 )>> 1);
            return temp * temp * base;
        }
    }
}

运行结果:

0.037037037037037035
729.0


面试题13:在O(1)时间删除链表结点

题目大致为:
    给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。
思路:
    想要在O(1)时间内删除链表的指定结点,要遍历的话得O(n),则肯定不能遍历。若是要删除的结点不是尾结点,那么可以将后面的那个值复制到该指针处,并将后面指针所指空间删除,用复制+删除后面的实现删除,时间复杂度为O(1)。对于尾结点,需要遍历,那么时间复杂度是O(n),但是总的时间复杂度为[(n-1)*O(1)+O(n)]/n,结果是O(1)。
    【注意】链表只有一个节点,切要删除该节点(即头结点),是无法办到的,这点在《参考》中未提及。

package cn.learn.test;

public class MainTest {

    public static void main(String[] args) {
        // 构建链表  
        ListNode head = new ListNode(1);  
        ListNode node_2 = new ListNode(2);  
        ListNode node_3 = new ListNode(3);  
        ListNode node_4 = new ListNode(4);  
        ListNode node_5 = new ListNode(5);  
        ListNode node_6 = new ListNode(6);  
        ListNode node_7 = new ListNode(7);  
        head.setNext(node_2);  
        node_2.setNext(node_3);  
        node_3.setNext(node_4);  
        node_4.setNext(node_5);  
        node_5.setNext(node_6);  
        node_6.setNext(node_7);  
        node_7.setNext(null);  
        // 输出原始链表  
        System.out.println("原始链表:");  
        printList(head);  
        System.out.println("----------------");  
  
        // 删除结点node_3  
        deleteNode(head, node_3);  
        System.out.println("删除node_3后链表:");  
        printList(head);  
        System.out.println("----------------");  
  
        // 删除结点head  
        deleteNode(head, head);  
        System.out.println("删除head后链表:");  
        printList(head);  
        System.out.println("----------------");  
        
    }
    
    public static void deleteNode(ListNode head, ListNode toBeDeleted) {
        if (toBeDeleted == null || head == null) return;
        if (toBeDeleted.next != null) {  //删除的是中间节点
            ListNode temp = toBeDeleted.next;
            toBeDeleted.value = temp.value;
            toBeDeleted.next = temp.next;
        }
//        【注意】这部分代码不起作用,故注释了。
//        else if (head == toBeDeleted) {
//            // 如果头结点就是要删除的节点  
//            head = null;  
//        } 
        else {
            ListNode temp = head;
            while (temp.next != toBeDeleted) {
                temp = temp.next;
            }
            temp.next = null;
        }
    }
    
    /** 
     * 打印链表 
     *  
     * @param head头指针 
     */  
    public static void printList(ListNode head) {  
        ListNode current = head;  
        while (current != null) {  
            System.out.print(current.getValue() + "、");  
            current = current.getNext();  
        }  
        System.out.println();  
    }  
}

class ListNode {
    int value;
    ListNode next;

    public ListNode(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public ListNode getNext() {
        return next;
    }

    public void setNext(ListNode next) {
        this.next = next;
    }
}
运行结果:
原始链表:
1、2、3、4、5、6、7、
----------------
删除node_3后链表:
1、2、4、5、6、7、
----------------
删除head后链表:
2、4、5、6、7、
----------------


面试题14:调整数组顺序使奇数位于偶数前面

题目大致为:

    对于一个数组,实现一个函数使得所有奇数位于数组的前半部分,偶数位于数组的后半部分。

思路:

    可以使用双指针的方式,一个指针指向数组的开始,一个指针指向数组的尾部,如果头部的数为偶数且尾部的数是奇数则交换,否则头部指针向后移动,尾部指针向前移动,直到两个指针相遇

   【注意】这里没有要求调整前后奇数的相对位置和偶数相对位置一致。

Java代码:

public class MainTest {

    public static void main(String[] args) {
        int arr[] = {1, 2, 3, 4, 5, 6};
        rejectArray(arr);
        System.out.println(Arrays.toString(arr));
    }
    
    public static void rejectArray(int[] arr) {
        int l = 0, r = arr.length - 1;
        while (l < r) {
            if (arr[l] % 2 == 1) {
                l++;
            } else if (arr[l] % 2 == 0 && arr[r] % 2 == 1) {
                int temp = arr[l];
                arr[l] = arr[r];
                arr[r] = temp;
                l++;
                r--;
            } else {
                r--;
            }
        }
    }
}
运行结果:

[1, 5, 3, 4, 2, 6]




面试题15:链表中倒数第k个结点

题目大致为:

    在一个链表中,查找倒数的第k个数。

思路:

    使用双指针的方式,前一个指针先走k步(中间隔k-1个结点),后一个指针才开始走,直到第一个指针走到尾,后一个指针指向的就是要找的倒数第k个数。值得注意的是:1、k是否超过链表长度且k必须为正整数;2、链表是否为空。

Java代码:

public class MainTest {
    public static void main(String[] args) {
        // 构建链表  
        ListNode head = new ListNode(1);  
        ListNode h1 = new ListNode(2);  
        ListNode h2 = new ListNode(3);  
        ListNode h3 = new ListNode(4);  
        ListNode h4 = new ListNode(5);  
        ListNode h5 = new ListNode(6);  
        head.setNext(h1);  
        h1.setNext(h2);  
        h2.setNext(h3);  
        h3.setNext(h4);  
        h4.setNext(h5);  
        h5.setNext(null);  
        // 查找倒数第k个  
        ListNode p = findKthToTail(head, 3);  
        System.out.println(p.getValue());  
    }
    
    public static ListNode findKthToTail(ListNode head, int k) {
        if (head == null || k <= 0) {
            return null;
        }
        ListNode prePoint = head;
        ListNode postPost = head;
        while (k-- > 0) {
            prePoint = prePoint.next;
            if (prePoint == null) {
                return null;
            }
        }
        while (prePoint != null) {
            prePoint = prePoint.next;
            postPost = postPost.next;
        }
        return postPost;
    }
}

class ListNode {
    int value;
    ListNode next;

    public ListNode(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public ListNode getNext() {
        return next;
    }

    public void setNext(ListNode next) {
        this.next = next;
    }
}
运行结果:

4

面试题16:反转链表

题目大致为:
    对于一个链表,反转该链表并返回头结点。
思路:
    主要是指针的操作,但是要注意不能断链。这里可以使用非递归的方式求解。
Java代码

public class MainTest {
    public static void main(String[] args) {
        // 构建链表  
        ListNode head = new ListNode(1);  
        ListNode h1 = new ListNode(2);  
        ListNode h2 = new ListNode(3);  
        ListNode h3 = new ListNode(4);  
        ListNode h4 = new ListNode(5);  
     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值