【解题报告】《LeetCode零基础指南》(第四讲) 一维数组 - Java

本文介绍了数组的基本概念、创建方法及常用API,包括动态初始化和静态初始化。接着详细讲解了几道经典的算法题,如搜索旋转排序数组、寻找最小值和爬楼梯问题,涉及到二分查找、动态规划等算法思想。此外,还涵盖了斐波那契数列、泰波那契数的计算,以及数组操作在不同场景的应用,如寻找差的绝对值为K的数对数目。文章通过代码示例深入浅出地展示了数组和算法在实际问题中的应用。
摘要由CSDN通过智能技术生成

在这里插入图片描述

零、数组

1. 数组的概念

  1. 数组是一个用于存储多个相同类型数据的集合,创建数组时是把数组的地址实际上是哈希值)赋值给变量,例如:[I@677327b6。
  2. 数组是引用数据类型,也是一种特殊的对象。
  3. 数组一旦创建,长度不可改变

2. 数组的创建

  • 数组的创建有3种语法:
    • 静态初始化(2种)
      • int[] a = {5,1,2,3,8,9};
        直接赋予初始值
      • a = new int[]{4,6,1};
        为存在的数组变量,重新赋予一个新的数组,并且,直接初始化数组数据
    • 动态初始化(1种)
      • int[] a = new int[5];
        新建5个长度的int[]数组,存默认值0,需要后续自己初始化数组数据

3. 创建数组过程分析

以 int[] a = new int[5]为例

  • 在内存中开辟连续的空间,用来存放数据,长度是5
  • 给数组完成初始化过程,给每个元素赋予默认值,int类型默认值是0
  • 数组完成初始化会分配一个唯一的地址值(哈希值)
  • 把唯一的地址值交给引用类型的变量 a a a 去保存

4. 常用的数组API

  • 1、Arrays.toString(a)
    • 把数组中的数据拼接成字符串
  • 2、Arrays.sort(a)
    • 数组排序,基本类型数组为优化的快速排序,引用类型数组为优化的合并排序
  • 3、Arrays.binarySearch(a,t)
    • 二分法查找(折半查找),在有序的数组中查找目标值的位置下标,找不到就返回 -(插入点+1)
  • 4、Arrays.copyOf(a,指定长度)
    • 把数组 a a a 复制成指定长度的新数组(此方法会创建新数组
  • 5、System.arraycopy(原数组,原数组起始位置(即下标),目标数组,目标数组起始位置,复制数量)
    • 数组复制方法,此方法复制数组后不会创建新数组

一、33. 搜索旋转排序数组

1.题目

33. 搜索旋转排序数组

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

2.分析

这道题无用的文字太多,简单来说就是:

  • 遍历数组,当遍历到的元素跟目标元素 t a r g e t target target 相同,返回当前下标,遍历结束都没找到返回 − 1 -1 1

3.代码

class Solution {
    public int search(int[] nums, int target) {
        int i;
        for (i = 0;i < nums.length;i++){
            if (nums[i] == target){
                return i;
            }
        }
        return -1;
    }
}

在这里插入图片描述

二、81. 搜索旋转排序数组 II

1.题目

81. 搜索旋转排序数组 II

给你 旋转后 的数组 nums 和一个整数 target ,请你编写一个函数来判断给定的目标值是否存在于数组中。如果 nums 中存在这个目标值 target ,则返回 true ,否则返回 false 。

2.分析

跟第一题差不多,只是把方法的返回值改成布尔类型 (true / false)。

3.代码

class Solution {
    public boolean search(int[] nums, int target) {
        int i;
        for (i = 0;i < nums.length;i++){
            if (nums[i] == target){
                return true;
            }
        }
        return false;
    }
}

在这里插入图片描述

三、153. 寻找旋转排序数组中的最小值

1.题目

153. 寻找旋转排序数组中的最小值

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

提示:
-5000 <= nums[i] <= 5000

2.分析

  1. 定义一个用于存储最小值的变量 m i n min min,因为提示中提到 n u m s [ i ] < = 5000 nums[i] <= 5000 nums[i]<=5000,所以 m i n min min 可以初始化为5000。
  2. 遍历数组,因为这里确定要遍历所有元素并且不需要获取下标值,可以使用增强for循环
  3. 通过三元运算符来判断,是否将当前遍历的值存入变量 m i n min min
  4. 最后返回变量 m i n min min

3.代码

class Solution {
    public int findMin(int[] nums) {
        int min = 5000;
        //增强for循环,确定要遍历全部元素并且不需要获取下标值时可以使用
        for (int num : nums) {
            min = min < num ? min : num;
        }
        return min;
    }
}

在这里插入图片描述

四、70. 爬楼梯

1.题目

70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。

2.分析

  • 这道题用到动态规划(DP)。
  • 假设爬上 n n n 阶楼梯的方法数为 d p [ n ] dp[n] dp[n]
    因为爬上 n n n 阶楼梯的上一步,这个人必定是在 ( n − 1 ) (n-1) (n1) ( n − 2 ) (n-2) (n2) 阶楼梯上,所以:
    n 阶 楼 梯 的 方 法 数 = ( n − 1 ) 阶 楼 梯 的 方 法 数 + ( n − 2 ) 阶 楼 梯 的 方 法 数 n 阶楼梯的方法数 = (n-1) 阶楼梯的方法数 + (n-2) 阶楼梯的方法数 n=(n1)+(n2) 即 : d p [ n ] = d p [ n − 1 ] + d p [ n − 2 ] 即:dp[n]=dp[n-1]+dp[n-2] dp[n]=dp[n1]+dp[n2]
  • 首先确定1阶和2阶的方法数分别为: d p [ 1 ] = 1 , d p [ 2 ] = 2 dp[1]=1,dp[2]=2 dp[1]=1,dp[2]=2
  • 最后通过一维数组来存储 n n n 阶以前各阶的方法数,经过遍历就能得到 d p [ n ] dp[n] dp[n]

3.代码

class Solution {
    public int climbStairs(int n) {
    	//这里定义数组长度为n + 3,是为了防止 n<3 时数组越界
        int[] dp = new int[n + 3];
        dp[1] = 1;
        dp[2] = 2;
        int i;
        for (i = 3;i <= n;i++){
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}

在这里插入图片描述

五、斐波那契数

1.题目

509. 斐波那契数

F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1

2.分析

  • 有两种方法:
    • 1、递归(内存消耗低,但用时长
      确定递归的终点: n = 0 或 n = 1 n = 0 或n = 1 n=0n=1
      当前 n n n 的值 = ( n − 1 ) (n - 1) (n1) 调用该方法得到的值 + ( n − 2 ) (n - 2) (n2) 调用该方法得到的值
    • 2、动态规划
      跟第四题一样,利用一维数组将 n n n 之前的数据存储下来,最后返回 d p [ n ] dp[n] dp[n]

3.代码

  • 1、递归

    class Solution {
        public int fib(int n) {
            if (n == 0 || n == 1){
                return n;
            }
            return fib(n - 1) + fib(n - 2);
        }
    }
    

    在这里插入图片描述

  • 2、动态规划

    class Solution {
        public int fib(int n) {
        	//这里定义数组长度为n + 2,是为了防止 n<2 时数组越界
            int[] dp = new int[n + 2];
            dp[0] = 0;
            dp[1] = 1;
            int i;
            for (i = 2;i <= n;i++){
                dp[i] = dp[i - 1] + dp[i - 2];
            }
            return dp[n];
        }
    }
    

    在这里插入图片描述

六、1137. 第 N 个泰波那契数

1.题目

1137. 第 N 个泰波那契数

泰波那契序列 Tn 定义如下:
T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2
给你整数 n,请返回第 n 个泰波那契数 Tn 的值。

2.分析

  • 同样是利用动态规划,这里换一种写法,可以不用定义数组来存储元素。
  • 只需要定义多个变量来存储上一步得到的值,就可以用作当前步骤 T n T_n Tn 的求解,如下图所示:
    在这里插入图片描述

3.代码

class Solution {
    public int tribonacci(int n) {
        if (n == 0 || n == 1){
            return n;
        }
        if (n == 2){
            return 1;
        }
        int i,target = 0,n1 = 0,n2 = 1,n3 = 1;
        for (i = 3;i <= n;i++){
            target = n1 + n2 + n3;
            n1 = n2;
            n2 = n3;
            n3 = target;
        }
        return target;
    }
}

在这里插入图片描述

七、2006. 差的绝对值为 K 的数对数目

1.题目

2006. 差的绝对值为 K 的数对数目

给你一个整数数组 nums 和一个整数 k ,请你返回数对 (i, j) 的数目,满足 i < j 且 |nums[i] - nums[j]| == k 。
|x| 的值定义为:
如果 x >= 0 ,那么值为 x 。
如果 x < 0 ,那么值为 -x 。

2.分析

  • 这题可以暴力两层循环解决,这里换一种思路:
    • 定义一个map,然后遍历数组,记录数组元素以及对应出现的次数
    • 遍历map集合,每次在map集合中找是否存在 k e y = k e y + k key=key+k key=key+k ,如果存在,返回 k e y + k key+k key+k 对应的 v a l u e value value,与当前 k e y key key v a l u e value value 相乘,就是这两个元素 k e y key key k e y + k key+k key+k 能组成的所有数对数目
    • 最后累加到计数变量 c o u n t count count

3.代码

class Solution {
    public int countKDifference(int[] nums, int k) {
        int count = 0;
        HashMap<Integer,Integer> map = new HashMap<>();
        //遍历存储数字以及对应出现的次数
        for (int num : nums) {
            int value = map.getOrDefault(num, 0);
            map.put(num, ++value);
        }
        //遍历map集合
        Iterator<Map.Entry<Integer, Integer>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<Integer, Integer> next = iterator.next();
            count += map.getOrDefault(next.getKey() + k,0) * next.getValue();
        }
        return count;
    }
}

在这里插入图片描述

八、LCP 01. 猜数字

1.题目

LCP 01. 猜数字

小A 和 小B 在玩猜数字。小B 每次从 1, 2, 3 中随机选择一个,小A 每次也从 1, 2, 3 中选择一个猜。他们一共进行三次这个游戏,请返回 小A 猜对了几次?
输入的guess数组为 小A 每次的猜测,answer数组为 小B 每次的选择。guess和answer的长度都等于3。

2.分析

遍历数组,只要 g u e s s [ i ] = = a n s w e r [ i ] guess[i] == answer[i] guess[i]==answer[i],则计数加 1 1 1

3.代码

class Solution {
    public int game(int[] guess, int[] answer) {
        int i,count = 0;
        for (i = 0;i < 3;i++){
            if (guess[i] == answer[i]){
                count++;
            }
        }
        return count;
    }
}

在这里插入图片描述

九、LCP 06. 拿硬币

1.题目

LCP 06. 拿硬币

桌上有 n 堆力扣币,每堆的数量保存在数组 coins 中。我们每次可以选择任意一堆,拿走其中的一枚或者两枚,求拿完所有力扣币的最少次数。

限制:
1 <= n <= 4
1 <= coins[i] <= 10

2.分析

  • 分两种情况:
    • 1.偶数个数的直接2个2个拿完
    • 2.奇数个数的,先2个2个拿,最后剩下1个再一次拿走
  • 代码中把上述过程转换成位运算的写法,当然也可以直接写除号“/”,取余“%”等。

3.代码

class Solution {
    public int minCount(int[] coins) {
        int count = 0;
        for (int coin : coins) {
            //coin是偶数
            if ((coin & 1) == 0){
                count += coin >> 1;
            //coin是奇数
            } else {
                count += (coin >> 1) + 1;
            }
        }
        return count;
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值