《代码随想录》刷题笔记——数组篇【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;
}


目录
相关文章
|
5天前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
|
19天前
|
XML 安全 Java
Java反射机制:解锁代码的无限可能
Java 反射(Reflection)是Java 的特征之一,它允许程序在运行时动态地访问和操作类的信息,包括类的属性、方法和构造函数。 反射机制能够使程序具备更大的灵活性和扩展性
33 5
Java反射机制:解锁代码的无限可能
|
15天前
|
安全 Java 编译器
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
|
15天前
|
jenkins Java 测试技术
如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例详细说明
本文介绍了如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例,详细说明了从 Jenkins 安装配置到自动构建、测试和部署的全流程。文中还提供了一个 Jenkinsfile 示例,并分享了实践经验,强调了版本控制、自动化测试等关键点的重要性。
48 3
|
21天前
|
存储 安全 Java
系统安全架构的深度解析与实践:Java代码实现
【11月更文挑战第1天】系统安全架构是保护信息系统免受各种威胁和攻击的关键。作为系统架构师,设计一套完善的系统安全架构不仅需要对各种安全威胁有深入理解,还需要熟练掌握各种安全技术和工具。
59 10
|
15天前
|
Java 开发工具 Android开发
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
|
15天前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
Kotlin教程笔记(28) -Kotlin 与 Java 混编
|
16天前
|
分布式计算 Java MaxCompute
ODPS MR节点跑graph连通分量计算代码报错java heap space如何解决
任务启动命令:jar -resources odps-graph-connect-family-2.0-SNAPSHOT.jar -classpath ./odps-graph-connect-family-2.0-SNAPSHOT.jar ConnectFamily 若是设置参数该如何设置
|
15天前
|
Java
Java代码解释++i和i++的五个主要区别
本文介绍了前缀递增(++i)和后缀递增(i++)的区别。两者在独立语句中无差异,但在赋值表达式中,i++ 返回原值,++i 返回新值;在复杂表达式中计算顺序不同;在循环中虽结果相同但使用方式有别。最后通过 `Counter` 类模拟了两者的内部实现原理。
Java代码解释++i和i++的五个主要区别
|
23天前
|
搜索推荐 Java 数据库连接
Java|在 IDEA 里自动生成 MyBatis 模板代码
基于 MyBatis 开发的项目,新增数据库表以后,总是需要编写对应的 Entity、Mapper 和 Service 等等 Class 的代码,这些都是重复的工作,我们可以想一些办法来自动生成这些代码。
30 6