剑指offer一

最近在看《剑指offer》,写几篇文章来记录一下,今天有以下几道算法题:

  • 斐波那契数列
  • 数组中重复的数字
  • 二维数组中的查找
  • 替换空格

斐波那契数列

写一个函数,输入n,求斐波那契数列的第n项。

递归解法重复计算太多,效率太低,这里我们使用时间复杂度为O(n)的方法。

解题思路

从下往上计算,首先根据f(0)和f(1)算出f(2),再根据f(1)和f(2)算出f(3)…….以此类推就可以算出第n项。

代码实现

public class Fibonacci {

    public static long fibonacci(long n){
        
        if (n<0)  throw new RuntimeException("无效的输入");
        if (n==0) return 0;
        if (n==1) return 1;

        long fibOne=0;
        long fibTwo=1;
        long fibSum=0;

        for (int i = 2; i <= n; i++) {            
            fibSum=fibOne+fibTwo;
            fibOne=fibTwo;
            fibTwo=fibSum;
        }
        return fibSum;
    }
}

数组中重复的数字

在一个长度为n的数组里的所有数字都在0到n-1的范围。数组中某些数字是重复的,但不知道有几个数字重复,也不知道每个数字重复的次数。 请找出数组中任意一个重复的数字。例如如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。

解题思路

我们注意到数组中的数字都在0n-1的范围内。如果这个数组中没有重复的数字,那么当数组排序后数字i将出现在下标为i的位置。

步骤

从头到尾扫描这个数组中的每个数字。当扫描到下标为i的数字的时候,首先比较这个数字(用m表示)是不是i。 如果是,接着扫描下一个数字。如果不是,再拿它和第m个数字进行比较。 如果它和第m个数字相等,就找到一个重复的数字(该数字在下标为i和m的位置都出现了)。 如果它和第m个数字不想等,就把第i个数字和第m个数字交换,把m放到属于它的位置。 接下来再重复这个比较,交换的过程,直到发现一个重复的数字。

以数组{2,3,1,0,2,5,3}为例来分析找到重复数字的步骤。数组的第0个数字(从0开始计数,和数组的下标保持一致)是2, 与它的下标不相等,于是把它和下标为2的数字1交换,交换后的数组是{1,3,2,0,2,5,3}。 此时第0 个数字是1,仍然与它的下标不相等,继续把它和下标为1的数字3交换,得到数组{0,1,2,3,2,5,3}。 此时第0 个数字为0,接着扫描下一个数字,在接下来的几个数字中,下标为1,2,3的三个数字分别为1,2,3, 他们的下标和数值都分别相等,因此不需要做任何操作。 接下来扫描下标为4的数字2.由于它的值与它的下标不相等,再比较它和下标为2的数字。 注意到此时数组中下标为2的数字也是2,也就是数字2和下标为2和下标4的两个位置都出现了,因此找到一个重复的数字。

代码实现

public class Test {

    public static int duplication;//用来保存重复数字
    
    public static boolean duplicate(int[] arr) {
        //判断输入是否合法
        if (arr == null || arr.length == 0) {
            return false;
        }
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] < 0 || arr[i] >= arr.length) {
                return false;
            }
        }
        //核心代码
        for (int i = 0; i < arr.length; i++) {
            while (arr[i] != i) {
                //如果两个数相等则返回true
                if (arr[i] == arr[arr[i]]) {
                    duplication = arr[i];
                    System.out.println(arr[i]);
                    return true;
                }
                //否则交换数字
                int temp = arr[i];
                arr[i] = arr[temp];
                arr[temp] = temp;
            }
        }
        return false;
    }
}

二维数组的查找

在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。 请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

解题思路

(1)首先选取数组中右上角的数字。如果该数字等于要查找的数字,则结束查找过程。
(2)如果该数字大于要查找的数字,则剔除这个数字所在的列。
(3)如果该数字小于要查找的数字,则剔除这个数字所在的行。

代码实现

public class Test {

    public static boolean find(int[][] matrix, int number) {
 
        if (matrix == null || matrix.length < 1 || matrix[0].length < 1) {
            return false;
        }
 
        int rows = matrix.length; // 数组的行数
        int cols = matrix[1].length; // 数组行的列数
 
        int row = 0; // 起始开始的行号
        int col = cols - 1; // 起始开始的列号
 
        while (row >= 0 && row < rows && col >= 0 && col < cols) {           
            if (matrix[row][col] == number) { // 如果找到了就直接退出
                return true;
            } else if (matrix[row][col] > number) {
                col--; // 列数减一,代表向左移动
            } else { // 
                row++; // 行数加一,代表向下移动
            }
        } 
        return false;
    } 
}
  

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理