HOT100-技巧类型题

核心思想

HOT100-技巧类型题

例题

1 只出现一次的数字

题目描述:

给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

示例 1 :

**输入:**nums = [2,2,1]

**输出:**1

示例 2 :

**输入:**nums = [4,1,2,1,2]

**输出:**4

示例 3 :

**输入:**nums = [1]

**输出:**1

提示:

  • 1 <= nums.length <= 3 * 104
  • -3 * 104 <= nums[i] <= 3 * 104
  • 除了某个元素只出现一次以外,其余每个元素均出现两次。

解题思路:

  • 使用性质:0n=n,nn=0,偶数次的利用结合律最后异或完都会为0,奇数次的最后异或结果为其本身
  • 异或运算的结合律,交换律

代码如下

Java 复制代码
class Solution {

    public int singleNumber(int[] nums) {

        int all=0;

        for(int num:nums){

            all^=num;

        }

        return all;

    }

}

2、多数元素

题目描述:

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

**输入:**nums = [3,2,3]

**输出:**3

示例 2:

**输入:**nums = [2,2,1,1,1,2,2]

**输出:**2

提示:

  • n == nums.length
  • 1 <= n <= 5 * 104
  • -109 <= nums[i] <= 109
  • 输入保证数组中一定有一个多数元素。

**进阶:**尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。

解题思路:

  • 把相同元素当作同一个阵营的人,人数等于阵营血量
  • 那么次数大于大于 ⌊ n/2 ⌋ 的元素是其中血量最厚的那个
  • 阵营间大战,不同阵营一换一
  • 阵营之间作战,最后还剩下的血量不为0的就是寻找的阵营

代码如下

Java 复制代码
class Solution {

    public int majorityElement(int[] nums) {

        //记录最终答案

        int ans=0;

        //记录答案出现次数,即ans的血量

        int hp=0;

  

        for(int num:nums){

            if(hp==0){

                ans=num;

                hp=1;

            }else{

                //若双方同阵营,则加血

                hp+=num==ans?1:-1;

            }

        }

        return ans;

    }

}

3、 颜色分类

题目描述:

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

我们使用整数 012 分别表示红色、白色和蓝色。

必须在不使用库内置的 sort 函数的情况下解决这个问题。

示例 1:

**输入:**nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

示例 2:

**输入:**nums = [2,0,1]
输出:[0,1,2]

提示:

  • n == nums.length
  • 1 <= n <= 300
  • nums[i]012

进阶:

  • 你能想出一个仅使用常数空间的一趟扫描算法吗?

解题思路:

  • 首先这个题的数据只有0,1,2
  • 需要以O (N) 的时间复杂度,O (1) 的空间复杂度完成
  • 步骤如下
    • 步骤1 :初始化 p0p1 分别指向下一个放 0 和 1 的位置,原因是用它们动态划分出 0 区和 1 区的边界。
    • 步骤2 :从左到右遍历每个位置 i 取出原值 num原因是单趟扫描要求每个元素只处理一次。
    • 步骤3 :先把 nums[i] 直接设为 2,原因是把当前位置先当作默认的 2 区并清空旧值避免干扰。
    • 步骤4 :若 num<=1 就在 p1 处写 1 并 p1++原因是 0 或 1 都会让 1 区向右扩展一格(0 先占位)。
    • 步骤5 :若 num==0 再在 p0 处写 0 并 p0++原因是把真正的 0 放进最前面的 0 区并覆盖刚才的占位 1。

代码如下

Java 复制代码
class Solution {

    public void sortColors(int[] nums) {

        //下一个应该放置0/1的位置

        int p0=0;

        int p1=0;

        for(int i=0,num;i<nums.length;i++){

            num=nums[i];

            //先让nums[i]被2覆盖

            nums[i]=2;

            //再让nums[i]为1

            if(num<=1){

                nums[p1++]=1;

            }

            //让nums[i]

            if(num==0){

                nums[p0++]=0;

            }

        }

    }

}

4、下一个排列

题目描述:

整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。

  • 例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3][1,3,2][3,1,2][2,3,1]

整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。

  • 例如,arr = [1,2,3] 的下一个排列是 [1,3,2]
  • 类似地,arr = [2,3,1] 的下一个排列是 [3,1,2]
  • arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。

给你一个整数数组 nums ,找出 nums 的下一个排列。

必须 原地 修改,只允许使用额外常数空间。

示例 1:

**输入:**nums = [1,2,3]
输出:[1,3,2]

示例 2:

**输入:**nums = [3,2,1]
输出:[1,2,3]

示例 3:

**输入:**nums = [1,1,5]
输出:[1,5,1]

提示:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 100

解题思路:

  • 从右向左,找第一个小于右侧相邻数字的数 x
  • 找 x 右边最小的大于 x 的数 y,交换 x 和 y
  • 反转 y 右边的数,把右边的数变成最小的排列

代码如下

Java 复制代码
class Solution {

    public void nextPermutation(int[] nums) {

        int n = nums.length;

        //寻找数组中最后一个有上升趋势的位置,例如num[i]<num[i+1],这就是一个上升趋势,pos取i值

        int pos = n - 2;

        while (pos >= 0 && nums[pos] >= nums[pos + 1]) {

            pos--;

        }

        //说明找到了最后的一个上升趋势

        if (pos >= 0) {

            //找到pos右侧大于pos指向的数的最小的那个

            //由于pos是最后一个上升趋势,因此pos+1往后的数一定是一个递减的序列

            int j = n - 1;

            while (nums[j] <= nums[pos]) {

                j--;

            }

            swap(nums, pos, j);

            //这样交换后,由于j是大于pos的最小的数,所以交换后pos+1往后仍然是一个非递增序列

        }

        //现在交换完后,当前字典序已经大于之前的了,但是我们是要找下一个,也就是以前缀[0....pos]后缀[pos+1...n-1]最小的那个

        //即pos+1是一个非递增,将其逆序,变为非递减

        reverse(nums, pos + 1, n - 1);

    }

  

    public void swap(int[] nums, int i, int j) {

        int temp = nums[i];

        nums[i] = nums[j];

        nums[j] = temp;

    }

  

    public void reverse(int[] nums, int i, int j) {

        while (i <= j) {

            int temp = nums[i];

            nums[i] = nums[j];

            nums[j] = temp;

            i++;

            j--;

        }

    }

}

5、寻找重复数

题目描述:

给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1n),可知至少存在一个重复的整数。

假设 nums 只有 一个重复的整数 ,返回 这个重复的数

你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。

示例 1:

**输入:**nums = [1,3,4,2,2]

**输出:**2

示例 2:

**输入:**nums = [3,1,3,4,2]

**输出:**3

示例 3 :

**输入:**nums = [3,3,3,3,3]

**输出:**3

提示:

  • 1 <= n <= 105
  • nums.length == n + 1
  • 1 <= nums[i] <= n
  • nums只有一个整数 出现 两次或多次 ,其余整数均只出现 一次

进阶:

  • 如何证明 nums 中至少存在一个重复的数字?
  • 你可以设计一个线性级时间复杂度 O(n) 的解决方案吗?

解题思路:

  • 这个题可以转化为一个环形链表模型,每个数字就变成了链表中的节点
  • 重复数字相当于环形链表环形入口,重复数值入度为2,其余节点入度为1
  • 转为环形链表模型后,解法其实和环形链表Ⅱ一样
  • 只不过这里由于给定结构是数组,那么链表的next指针就变为了nums[节点值]
  • 使用快慢双指针

代码如下

Java 复制代码
class Solution {

    public int findDuplicate(int[] nums) {

        int n=nums.length;

        if(nums==null || n<2){

            return -1;

        }

        //快慢双指针

        int slow=nums[0];

        int fast=nums[nums[0]];

        //快指针每次走2步,慢指针每次走一步

        while(slow!=fast){

            slow=nums[slow];

            fast=nums[nums[fast]];

        }

        //相同后,快指针从头出发,每次只走一步

        fast=0;

        while(slow!=fast){

            fast=nums[fast];

            slow=nums[slow];

        }

        return slow;

    }

}
相关推荐
superman超哥7 小时前
仓颉语言中基本数据类型的深度剖析与工程实践
c语言·开发语言·python·算法·仓颉
Learner__Q8 小时前
每天五分钟:滑动窗口-LeetCode高频题解析_day3
python·算法·leetcode
阿昭L8 小时前
leetcode链表相交
算法·leetcode·链表
闻缺陷则喜何志丹8 小时前
【计算几何】仿射变换与齐次矩阵
c++·数学·算法·矩阵·计算几何
liuyao_xianhui8 小时前
0~n-1中缺失的数字_优选算法(二分查找)
算法
hmbbcsm9 小时前
python做题小记(八)
开发语言·c++·算法
机器学习之心9 小时前
基于Stacking集成学习算法的数据回归预测(4种基学习器PLS、SVM、BP、RF,元学习器LSBoost)MATLAB代码
算法·回归·集成学习·stacking集成学习
图像生成小菜鸟9 小时前
Score Based diffusion model 数学推导
算法·机器学习·概率论
声声codeGrandMaster9 小时前
AI之模型提升
人工智能·pytorch·python·算法·ai
黄金小码农10 小时前
工具坐标系
算法