【剑指offer】数组

数组

2021/4/2

1.LC寻找两个正序数组的中位数

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

1.暴力破解法

思路:先将两数组合并,再排序,得到一个新的数组。然后分类讨论,如果为奇数数组,则‘/2’,得到中位数;如果为偶数数组,则‘/2’,得到一个数,然后序号加1,得到后一个数,两数相加再除2,得到中位数。

代码:

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int strLen1=nums1.length;//保存第一个数组长度
        int strLen2=nums2.length;//保存第二个数组长度
        nums1= Arrays.copyOf(nums1,strLen1+ strLen2);//扩容
        System.arraycopy(nums2, 0, nums1, strLen1,strLen2 );//将第二个数组与第一个数组合并
        
        Arrays.sort(nums1);
        if (nums1.length%2 == 1){
            double median = nums1[nums1.length/2];
            // System.out.println(median);
            return median;
        }else{
            double median = (double)(nums1[nums1.length/2]+nums1[nums1.length/2-1])/2;
            // System.out.println(median);
            return median;
        }
        
    }
}

难点:

  1. 数组合并,通过Arrays.copyof()和System.arraycopy()函数进行合并
  2. 如何保留小数不被整除?在前面加上(double)。

2.二分查找法(不会)

2021/4/5

专题:链表

2021/4/7

剑指offer

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
[
  [1,2,8,9],
  [2,4,9,12],
  [4,7,10,13],
  [6,8,11,15]
]
给定 target = 7,返回 true。

给定 target = 3,返回 false。


输入
7,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]

返回值
true

思路

  1. 暴力破解法。将二维数组循环遍历两边,然后通过if比对,输出结果
public class Solution {
    public boolean Find(int target, int [][] array) {
        for (int i = 0; i < array.length; i++){
            for(int j = 0; j < array[i].length; j++){
                if(target == array[i][j]){
                    return true;
                }
            }
        }
        return false;
    }
}
  1. 二分查找。

    二分查找的原理是:将1个排从小到大(从大到小)的数,分别在头和尾设置m,n,在中间设立mid=(m+n)/2,然后目标数为tar,如果mid>tar,则将mid变成尾,在m和mid之间寻找tar,再设置一个新的mid2=(m+mid)/2,以此类推,直到找到tar为止;如果mid<tar,则相反。

public class Solution {
    public boolean Find(int target, int [][] array) {
        // 判断数组是否为空
     int m = array.length;
     if (m == 0) return false;
     int n = array[0].length;
     if (n == 0) return false;
     int r = 0, c = n-1; // 右上角元素
     while (r<m && c>=0) {
         if (target == array[r][c]) {
             return true;
         }
         else if (target > array[r][c]) {
             ++r;
         }
         else {
             --c;
         }
     }
     return false;
    }
}

第二题

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)。
n\leq 39n≤39

思路:重点是要了解什么是斐波那契数列。斐波那契数列是从第3项开始,每一项等于前面2项之和。

public class Solution {
    public int Fibonacci(int n) {
        if(n == 0){
            return 0;
        }else if(n == 1){
            return 1;
        }else{
            int sum[] = new int[n+1];
            sum[0] = 0;
            sum[1] = 1;
            for(int i = 0; i < n-1; i++){
                sum[i+2] = sum[i] + sum[i+1];

            }
            return sum[n];
        }
        
        
    }
}

第三题

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

思路:先用for循环判断奇偶记录下奇数个数,然后用一个新的数组接收,用for循环判断

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param array int整型一维数组 
     * @return int整型一维数组
     */
    public int[] reOrderArray (int[] array) {
        // write code here
        int[] arr=new int[array.length];
        int num=0;
        for(int a:array){
            if((a&1)==1) num++;//奇数
        }
        int i=0;
        for(int a:array){
            if((a&1)==1){ //奇数
                arr[i++]=a;           
            }else{
                arr[num++]=a;
            }
        }
        return arr;
    }
}

重点:for循环那里,num代表奇数的个数,也就是num前面一定是奇数,后面一定是偶数,避免数组越界或者填充到0。

2021/4/8

第1题

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
输出:
[1,2,3,2,2,2,5,4,2]
返回值:
2

思路:

  1. 暴力破解法。先统计数组长度,确定其一半值,然后用两个for循环嵌套,累计每个数出现的次数,若某个数出现的次数等于或大于半值,则返回该数并退出,否则返回0.
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        //1.暴力破解法
        int num = array.length;
        int k = 0;
        for(int i:array){
            int add = 0;
            for(int j:array){
                if(i == j){
                    add++;
                }
            }
            if(add>num/2){
                k = i;
                break;
            }else{
                k = 0;
            }
        }
        return k;
    }
}
  1. 哈希。先将每一个数存入哈希表作为键,值为1,当有重复键时,值+1.最后判断每一个键,是否有超过半值的,有就输出键,没有返回1
import java.util.*;
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        //2.哈希
        int len = array.length;
        Map<Integer,Integer> map = new HashMap<>();
        for(int i : array){
            if(!map.keySet().contains(i)){
                map.put(i,1);
            }else{
                map.put(i,map.get(i)+1);
            }
        }
        for(Integer key: map.keySet()){
            if(map.get(key) > len/2){
                return key;
            }
        }
 
        return 0;
    }
}

第二题

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
输入:
[3,32,321]
返回值:
"321323"
  1. 思路:设置一个比较函数,若ab>ba,则设置一个之间temp变量,将a,b调换,保证小的再前面。用两个for循环嵌套,比较完之后,再将其转换为字符串拼接。
import java.util.ArrayList;

public class Solution {
    public String PrintMinNumber(int [] numbers) {
        String str = "";
        for(int i=0;i<numbers.length;i++){
            for(int j=i;j<numbers.length;j++){
                int a = Integer.valueOf(numbers[i]+""+numbers[j]);
                int b = Integer.valueOf(numbers[j]+""+numbers[i]);
                if(a>b){
                    int temp = numbers[i];
                    numbers[i] = numbers[j];
                    numbers[j] = temp;
                }
            }
        }
        for(int i : numbers){
            str += String.valueOf(i);
        }
        return str;
    }
}

第三题【简单】

给定一个数组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]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * ... * A[n-1],B[n-1] = A[0] * A[1] * ... * A[n-2];)
对于A长度为1的情况,B无意义,故而无法构建,因此该情况不会存在。
输入值:
[1,2,3,4,5]
返回值:
[120,60,40,30,24]

  1. 思路:重点是读懂题目。B[i]没有A[i]的乘阶,所以重点就变成了解决没有A[i]的问题。可以设置一个中间量temp,先将A[i]的值保存到temp中,等for循环结束再恢复数值。
import java.util.ArrayList;
public class Solution {
    public int[] multiply(int[] A) {
        int len = A.length;
        int[] b = new int[len];     
        for(int i=0;i<len;i++){
            int sum = 1;          
            int temp = A[i];
            A[i] = 1;        
            for(int j=0;j<len;j++){
                
                sum = sum*A[j];
            }
            b[i] = sum;
            
            A[i] = temp;
        }    
        return b;
    }
}

第四题

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

  1. 思路:运用哈希表,先将没出现过的值添加到键里面,当发现有重复的键时返回其键。
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param numbers int整型一维数组 
     * @return int整型
     */
    public int duplicate (int[] numbers) {
        // write code here
        int len = numbers.length;
        Map<Integer,Integer> map = new HashMap<>();
        for(int i : numbers){
            if(!map.keySet().contains(i)){
                map.put(i,1);
            }else{
                return i;
            }
        }
        return -1;
    }
}

2021/4/9

第一题

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

对于50\%50%的数据,size\leq 10^4size≤10 
4
 
对于75\%75%的数据,size\leq 10^5size≤10 
5
 
对于100\%100%的数据,size\leq 2*10^5size≤2∗10 
5
 输入:
 [1,2,3,4,5,6,7,0]
 返回值:
 7
  1. 暴力破解法。行不通,时间复杂度为O(n^2)太大,超时。
public class Solution {
    public int InversePairs(int [] array) {
        int mod = 1000000007;
        int len = array.length;
        int ret = 0;
        for(int i=0;i<len;i++){
            for(int j=i+1;j<len;j++){
                if(array[i]>array[j]){
                    ret += 1;
                    ret %= mod;
                }
            }
            
        }
        return ret;
    }
}
  1. 归并排序。(不会)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值