《代码随想录》刷题笔记——数组篇【java实现】

简介: 《代码随想录》刷题笔记——数组篇【java实现】

*二分查找

题目链接

https://leetcode.cn/problems/binary-search/

左闭右闭区间实现

  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)
/**
 * 左闭右闭写法
 *
 * @param nums
 * @param target
 * @return
 */
public static int search1(int[] nums, int target) {
    if (nums == null || nums.length == 0) {
        return -1;
    }
    int left = 0;
    int right = nums.length - 1;
    // 要是没有等号的话,在{5}里面找5就会出问题了
    while (left <= right) {
        int center = (left + right) / 2;
        if (target == nums[center]) {
            return center;
        } else if (target > nums[center]) {
            left = center + 1;
        } else {
            right = center - 1;
        }
    }
    return -1;
}

左闭右开区间实现

  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)
/**
 * 左闭右开写法
 *
 * @param nums
 * @param target
 * @return
 */
public static int search2(int[] nums, int target) {
    if (nums == null || nums.length == 0) {
        return -1;
    }
    int left = 0;
    // 区别点
    int right = nums.length;
    // 区别点
    while (left < right) {
        int center = (left + right) / 2;
        if (target == nums[center]) {
            return center;
        } else if (target > nums[center]) {
            left = center + 1;
        } else {
            // 区别点
            // 虽然已经知道center位置的元素不是要找的元素,但是因为是左闭右开,因此right还是指向center
            // 后面无论怎么循环,都不会再使用到center这个为止,因为center = (left + right) / 2永远小于right
            right = center;
        }
    }
    return -1;
}

*移除元素

题目链接

https://leetcode.cn/problems/remove-element/

暴力求解

  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)
public static int removeElement(int[] nums, int val) {
    int sameNum = 0;
    int i = 0;
    while (i < nums.length - sameNum) {
        if (val == nums[i]) {
            // 将后面的元素前移过来
            for (int j = i; j < nums.length - 1 - sameNum; j++) {
                nums[j] = nums[j + 1];
            }
            sameNum++;
        }
        if (val == nums[i]) {
            // 前移过来的数值和val一样,将i--
            i--;
        }
        i++;
    }
    return nums.length - sameNum;
}

双指针

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

【思想】

通过一个快指针和慢指针在一个for循环下完成两个for循环的工作,将快指针的值赋给慢指针


slow:新数组存储值的索引,因为每次存储完新数组的值,都会将slow++,因此最后直接返回slow即可,需要返回slow+1


fast:用来去前面探索那些不是val的值,然后将这个值赋给slow对应的位置

/**
 * 双指针
 *
 * @param nums
 * @param val
 * @return
 */
public static int removeElement1(int[] nums, int val) {
    int slow = 0;
    for (int fast = 0; fast < nums.length; fast++) {
        if (nums[fast] != val) {
            // 如果快指针找的数值不是val,就需要将其存储到新数组中
            // 同时slow++,以便存储下一个新数组的值
            nums[slow++] = nums[fast];
        }
    }
    return slow;
}

相向双指针法

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

上面的实现方法并没有改变元素的相对位置,相向双指针方法改变了元素相对位置,但是确保移动最少元素

/**
 * 想向双指针
 *
 * @param nums
 * @param val
 * @return
 */
public static int removeElement(int[] nums, int val) {
    int slow = 0, fast = nums.length - 1;
    while (slow <= fast) {
        // slow赋值为第一个等于val的索引
        while (slow <= fast) {
            if (nums[slow] != val) {
                slow++;
            } else {
                break;
            }
        }
        // fast赋值为最后一个等于val的索引
        while (fast >= slow) {
            if (nums[fast] == val) {
                fast--;
            } else {
                break;
            }
        }
        if (slow < fast) {
            nums[slow++] = nums[fast--];
        }
    }
    // slow最后一定指向的是 新数组末尾元素的下一个元素
    return slow;
}

*有序数组的平方

题目链接

https://leetcode.cn/problems/squares-of-a-sorted-array/

暴力求解

  1. 先对数组的每个元素求平方
  1. 对数组升序排序

时间复杂度:O(n)+排序算法的时间复杂度

双指针

【思路】

数组本身就是非递减顺序的,只不过负数在平方之后可能会变大,因此只需要用两端来比较就能知道那个数字的平方更大

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

public static int[] sortedSquares(int[] nums) {
    int left = 0, right = nums.length - 1;
    // 用于存储排序之后的结果
    int[] result = new int[nums.length];
    for (int i = nums.length - 1; i >= 0; i--) {
        int leftValue = nums[left];
        int rightValue = nums[right];
        if (leftValue * leftValue >= rightValue * rightValue) {
            result[i] = leftValue * leftValue;
            left++;
        } else {
            result[i] = rightValue * rightValue;
            right--;
        }
        System.out.println(Arrays.toString(result));
    }
    return result;
}

*长度最小的子数组

题目链接

https://leetcode.cn/problems/minimum-size-subarray-sum/

暴力求解

  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)

注意,子数组是原数组中连续的几个元素的集合

public int minSubArrayLen(int target, int[] nums) {
    // 最小子数组长度
    int minLen = nums.length + 1;
    for (int i = 0; i < nums.length; i++) {
        int sum = 0;
        for (int j = i; j < nums.length; j++) {
            sum += nums[j];
            if (sum >= target) {
                // 已经>=target,可以暂停了
                if ((j - i + 1) < minLen) {
                    minLen = j - i + 1;
                    break;
                }
            }
        }
    }
    return minLen == nums.length + 1 ? 0 : minLen;
}

部分案例已经超出时间限制

滑动窗口

  • 时间复杂度:O(n):不能以为for里放一个while就是O(n^2), 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)
  • 空间复杂度:O(1)
/**
 * 滑动窗口
 *
 * @param target
 * @param nums
 * @return
 */
public int minSubArrayLen1(int target, int[] nums) {
    // 最小子数组长度
    int minLen = nums.length + 1;
    int i = 0;
    int sum = 0;
    for (int j = 0; j < nums.length; j++) {
        // j++,窗口终止位置后移一位,sum添加相应的元素
        sum += nums[j];
        while (sum >= target) {
            // 窗口内的元素总和已经超过target,尝试将窗口的起始位置后移,即i++
            if ((j - i + 1) < minLen) {
                minLen = j - i + 1;
            }
            // sum移除窗口起始位置的元素值
            sum -= nums[i++];
        }
    }
    return minLen == nums.length + 1 ? 0 : minLen;
}

螺旋矩阵

【思想】

这道题主要是考代码能力,注意每次循环都是左开右闭就行

【我写的程序】

public static int[][] generateMatrix1(int n) {
    int[][] result = new int[n][n];
    int curNum = 1;
    int target = n * n;
    int initN = n;
    // 圈数
    int cirCleNum = 0;
    while (curNum <= target) {
        if (curNum == target) {
            result[cirCleNum][cirCleNum] = curNum;
            System.out.println("---------------------填中心---------------------");
            for (int i = 0; i < result.length; i++) {
                System.out.println(Arrays.toString(result[i]));
            }
            break;
        }
        // 填上边
        for (int i = 0; i < n - 1; i++) {
            result[cirCleNum][i + cirCleNum] = curNum++;
        }
        System.out.println("---------------------填上边---------------------");
        for (int i = 0; i < result.length; i++) {
            System.out.println(Arrays.toString(result[i]));
        }
        // 填右边
        for (int i = 0; i < n - 1; i++) {
            result[i + cirCleNum][initN - 1 - cirCleNum] = curNum++;
        }
        System.out.println("---------------------填右边---------------------");
        for (int i = 0; i < result.length; i++) {
            System.out.println(Arrays.toString(result[i]));
        }
        // 填下边
        for (int i = n - 1; i > 0; i--) {
            result[initN - 1 - cirCleNum][i + cirCleNum] = curNum++;
        }
        System.out.println("---------------------填下边---------------------");
        for (int i = 0; i < result.length; i++) {
            System.out.println(Arrays.toString(result[i]));
        }
        // 填左边
        for (int i = n - 1; i > 0; i--) {
            result[i + cirCleNum][cirCleNum] = curNum++;
        }
        System.out.println("---------------------填左边---------------------");
        for (int i = 0; i < result.length; i++) {
            System.out.println(Arrays.toString(result[i]));
        }
        System.out.println("======================================================================");
        cirCleNum += 1;
        n -= 2;
    }
    return result;
}

【别人的代码】

public int[][] generateMatrix(int n) {
    int loop = 0;  // 控制循环次数
    int[][] res = new int[n][n];
    int start = 0;  // 每次循环的开始点(start, start)
    int count = 1;  // 定义填充数字
    int i, j;
    while (loop++ < n / 2) { // 判断边界后,loop从1开始
        // 模拟上侧从左到右
        for (j = start; j < n - loop; j++) {
            res[start][j] = count++;
        }
        // 模拟右侧从上到下
        for (i = start; i < n - loop; i++) {
            res[i][j] = count++;
        }
        // 模拟下侧从右到左
        for (; j >= loop; j--) {
            res[i][j] = count++;
        }
        // 模拟左侧从下到上
        for (; i >= loop; i--) {
            res[i][j] = count++;
        }
        start++;
    }
    if (n % 2 == 1) {
        res[start][start] = count;
    }
    return res;
}


目录
相关文章
|
8天前
|
JavaScript NoSQL Java
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
152 96
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
|
30天前
|
存储 Java 开发者
【潜意识Java】深入详细理解分析Java中的toString()方法重写完整笔记总结,超级详细。
本文详细介绍了 Java 中 `toString()` 方法的重写技巧及其重要
51 10
【潜意识Java】深入详细理解分析Java中的toString()方法重写完整笔记总结,超级详细。
|
30天前
|
存储 Java C++
Java数组:静态初始化与动态初始化详解
本文介绍了Java中数组的定义、特点及初始化方式。
64 12
|
30天前
|
前端开发 JavaScript Java
Java构建工具-maven的复习笔记【适用于复习】
这篇文档由「潜意识Java」创作,主要介绍Maven的相关知识。内容涵盖Maven的基本概念、作用、项目导入步骤、依赖管理(包括依赖配置、代码示例、总结)、依赖传递、依赖范围以及依赖的生命周期等七个方面。作者擅长前端开发,秉持“得之坦然,失之淡然”的座右铭。期待您的点赞、关注和收藏,这将是作者持续创作的动力! [个人主页](https://blog.csdn.net/weixin_73355603?spm=1000.2115.3001.5343)
42 3
|
1月前
|
存储 Java 索引
Java快速入门之数组、方法
### Java快速入门之数组与方法简介 #### 一、数组 数组是一种容器,用于存储同种数据类型的多个值。定义数组时需指定数据类型,如`int[]`只能存储整数。数组的初始化分为静态和动态两种: - **静态初始化**:直接指定元素,系统自动计算长度,如`int[] arr = {1, 2, 3};` - **动态初始化**:手动指定长度,系统给定默认值,如`int[] arr = new int[3];` 数组访问通过索引完成,索引从0开始,最大索引为`数组.length - 1`。遍历数组常用`for`循环。常见操作包括求和、找最值、统计特定条件元素等。
|
1月前
|
存储 Java 索引
Java基础(六):数组
Java基础(六):数组
32 10
Java基础(六):数组
|
1月前
|
SQL Java 数据库连接
如何在 Java 代码中使用 JSqlParser 解析复杂的 SQL 语句?
大家好,我是 V 哥。JSqlParser 是一个用于解析 SQL 语句的 Java 库,可将 SQL 解析为 Java 对象树,支持多种 SQL 类型(如 `SELECT`、`INSERT` 等)。它适用于 SQL 分析、修改、生成和验证等场景。通过 Maven 或 Gradle 安装后,可以方便地在 Java 代码中使用。
272 11
|
1月前
|
JSON Java 数据挖掘
利用 Java 代码获取淘宝关键字 API 接口
在数字化商业时代,精准把握市场动态与消费者需求是企业成功的关键。淘宝作为中国最大的电商平台之一,其海量数据中蕴含丰富的商业洞察。本文介绍如何通过Java代码高效、合规地获取淘宝关键字API接口数据,帮助商家优化产品布局、制定营销策略。主要内容包括: 1. **淘宝关键字API的价值**:洞察用户需求、优化产品标题与详情、制定营销策略。 2. **获取API接口的步骤**:注册账号、申请权限、搭建Java开发环境、编写调用代码、解析响应数据。 3. **注意事项**:遵守法律法规与平台规则,处理API调用限制。 通过这些步骤,商家可以在激烈的市场竞争中脱颖而出。
|
2月前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
77 3