剑指offer

102 阅读4分钟

一、二维数组的查找

题目描述

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

思路

从右上开始往左下找,
如果大于target,就排除当前列,因为target(小)一定不在右边也不在下面,而是在左边,所以把列数col减一
如果小于target,就排除当前行,因为target(大)一定不在左边,只能在右边或者下面,并把行数row加一
综上,时间复杂度:O(行高 + 列宽)
     空间复杂度:O(1)

代码

public class Solution {
    public boolean Find(int target, int [][] array) {
        int rows = array.length;
        int cols = array[0].length;
        if(rows == 0)
            return false;
        if(cols == 0)
            return false;
        int row = 0;
        int col = cols - 1;
        while(row < rows && col >= 0){
            if(array[row][col] == target)
                return true;
            else if(array[row][col] < target)
                col--;
            else 
                row++;
        }
        return false;
    }
}

二、数组中重复的数字

题目描述

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

思路一

先排序,若左边和右边的数字相等,则返回该值
时间复杂度:O(nlogn)
空间复杂度:O(1)

代码

import java.util.*;
public class Solution {
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers == null || length == 0)
            return false;
        Arrays.sort(numbers);
        for(int i = 0; i < length-1; i++){
            if(numbers[i] == numbers[i+1]){
                duplication[0] = numbers[i]; 
                return true;
            }           
        }
        return false;
    }
}

思路二

利用HashSet,按顺序判断是否有重复,有就输出
时间复杂度:O(n)
空间复杂度:O(n)

代码

import java.util.*;
public class Solution {
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers == null || length == 0)
            return false;
        Set<Integer> set = new HashSet<>();
        for(int i = 0; i < length; i++){
            if(set.contains(numbers[i])){
                duplication[0] = numbers[i];
                return true;
            }               
            else
                set.add(numbers[i]);
        }
        return false;
        
    }
}

思路三

利用特性
时间复杂度:O(n)
空间复杂度:O(1)

代码

三、构建乘积数组

题目描述

给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],
其中B中的元素B[i]=A[0]A[1]...A[i-1]A[i+1]...A[n-1]。
不能使用除法。

思路

先计算左边的下三角的每一行
后把右边,从倒数第二行开始(倒数第一行已为结果),每次循环乘一个A[i]
时间复杂度:O(n)
空间复杂度:O(n)

代码

class Solution {
    public int[] constructArr(int[] a) {
        int len = a.length;
        if(a == null || len == 0)
            return a;
        
        int[] B = new int[len];
        B[0] = 1;
        for(int i =1; i < len; i++){
            B[i] = B[i-1] * a[i-1];
        }
        int temp = 1;
        for(int j = len-1; j >= 0; j--){
            //B[3],长度为4,最后一个已经确定,所以从B[2]开始,所以是长度减2
            B[j] *= temp;
            temp *= a[j];
            //B[1],j=1,
        }
        return B;
    }
}

四、在排序数组中查找数字 I

题目描述

统计一个数字在排序数组中出现的次数。

思路

有序->二分查找
找到之后,left往前倒数,right往后加,得到的总步数就是次数
时间复杂度:O(logn)
空间复杂度:O(1)

代码

class Solution {
    public int search(int[] nums, int target) {
        //有序一定要想到二分
        int index=find(nums,target);
        int left=index;
        int right=index+1;
        int count=0;
        while(left>=0&&nums[left]==target){
            count++;
            left--;
        }
        while(right<nums.length&&nums[right]==target){
            count++;
            right++;
        }
        return count;
    }
    public int find(int[] nums, int target){
        int left=0;
        int mid;
        int right=nums.length-1;
        while(left<=right){
            mid=(left+right)/2;
            if(nums[mid]>target){
                right=mid-1;
            }else if(nums[mid]<target){
                left=mid+1;
            }else{
                return mid;
            }
        }
        return -1;
    }
}

五、顺时针打印矩阵

题目描述

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

思路


代码


六、 翻转单词顺序

题目描述

输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。
为简单起见,标点符号和普通字母一样处理。
例如输入字符串"I am a student. ",则输出"student. a am I"

思路


代码