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


目录
相关文章
|
4天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
20 3
|
1月前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
52 24
|
12天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
49 2
|
24天前
|
安全 Java 编译器
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
|
24天前
|
Java 开发工具 Android开发
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
|
26天前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
66 5
|
26天前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
53 5
|
28天前
|
Java API 开发者
Java中的Lambda表达式:简洁代码的利器####
本文探讨了Java中Lambda表达式的概念、用途及其在简化代码和提高开发效率方面的显著作用。通过具体实例,展示了Lambda表达式如何在Java 8及更高版本中替代传统的匿名内部类,使代码更加简洁易读。文章还简要介绍了Lambda表达式的语法和常见用法,帮助开发者更好地理解和应用这一强大的工具。 ####
|
1月前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
Kotlin教程笔记(28) -Kotlin 与 Java 混编
33 2
|
23天前
|
Java 数据库连接 编译器
Kotlin教程笔记(29) -Kotlin 兼容 Java 遇到的最大的“坑”
Kotlin教程笔记(29) -Kotlin 兼容 Java 遇到的最大的“坑”
42 0