Leetcode热题100中的:技巧专题

前言

  • 只用Java。

136.只出现一次的数字

关键信息一句话总结:

利用异或的性质:a ^ a = 0,a ^ 0 = a,所有元素异或后剩下的就是只出现一次的数。

  • 难点1:只有一个数字出现了一次,怎么排除掉其他数字?
  • 分析1:可能是老老实实的计数,但是有邪门的方法。异或运算。a ^ 0 = a和a ^ a = 0。
java 复制代码
class Solution {
    public int singleNumber(int[] nums) {
        int total = 0;
        // 异或运算 a ^ 0 = a和a ^ a = 0
        // 那么 a ^ a ^ b => 0 ^ b = b
        for(int i = 0; i < nums.length; i++) {
            total ^= nums[i];
        }
        return total;
    }
}
  • 反思:我在洛谷做过这道题所以有点印象。我没有想到异或运算的性质,下一次遇到类似的数字的配对问题,可以考虑一下异或运算。

169.多数元素

关键信息一句话总结:

维护一个候选人 cand 和票数 cnt,相同就 cnt++,不同就 cnt--,cnt==0 时换候选人;最后候选人就是多数元素。摩尔投票。

  • 难点1:没有想到空间为O(1)的做法
  • 分析1:普通做法是用一个计数数组或者哈希表,但是空间O(n)。这一题是求众数,众数有个特点,就是个数大于其他数,那么众数出现的次数-遇到其他数的次数 > 0,好,那么就可以实现所谓的摩尔投票
java 复制代码
class Solution {
    public int majorityElement(int[] nums) {
        // 摩尔投票 算法原理:众数的数量大于其他数的数量
        int count = 0;
        int candidate = nums[0];
        for(int i = 0; i < nums.length; i++) {
            if(count == 0) {
                candidate = nums[i];
            }
            if(nums[i] == candidate) {
                count ++;
            } 
            if(nums[i] != candidate){
                count --;
            }
        }
        return candidate;
    }
}
  • 反思:我没有想到这种空间为O(1)的做法,我下次应该多考虑这种数的性质,就是要从性质和事实入手,用程序实现出这种思想,算法要注重原理,不是漫无目的的寻找,多观察事实的性质。

75.颜色分类

关键信息一句话总结:

三指针分区交换值

  • 方法1:三指针分区交换值,荷兰国旗问题
java 复制代码
class Solution {
    public void sortColors(int[] nums) {
        // 荷兰国旗问题 三指针分区 思想
        int left = 0;
        int right = nums.length - 1;
        int i = 0;
        while(i <= right) {
            if(nums[i] == 0) {
                swap(nums, i, left);
                left++;
                i++;
            } else if(nums[i] == 1) {
                i++;
            } else {
                swap(nums, i, right);
                right--;
            }
        }
    }
    private void swap(int[] nums, int a, int b) {
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }
}
  • 方法2:计数思想
java 复制代码
class Solution {
    public void sortColors(int[] nums) {
        int red = 0;
        int white = 0;
        int blue = 0;
        for(int i = 0; i < nums.length; i++) {
            if(nums[i] == 0) {
                red++;
            }
            if(nums[i] == 1) {
                white++;
            }
            if(nums[i] == 2) {
                blue++;
            }
        }
        int current = 0;
        while(red > 0) {
            nums[current] = 0;
            red--;
            current++;
        }
        while(white > 0) {
            nums[current] = 1;
            white--;
            current++;
        }
        while(blue > 0) {
            nums[current] = 2;
            blue--;
            current++;
        }
    }
}
  • 反思:我没有想到三指针分区,这道题想告诉我的是分区思想

31.下一个排列

关键信息一句话总结:

找到下降点,从后往前找到并交换第一个比他大的数,再将后半部分逆置

java 复制代码
class Solution {
    public void nextPermutation(int[] nums) {
        // 1.从右往左找第一个下降点 右边都是递增的
        int i = nums.length - 2;
        while(i >= 0 && nums[i] >= nums[i + 1]) {
            i--;
        }
        // 2.从右往左找第一个比 nums[i] 大的数 最小改变 交换第一个比它大的数
        if(i >= 0) {
            int j = nums.length - 1;
            while(nums[j] <= nums[i]) {
                j--;
            }
            swap(nums, i, j);
        }
        // 3.交换后,把 i+1 到结尾反转 因为反转一次保证字典序最小
        reverse(nums, i + 1);
    }
    private void swap(int[] nums, int a, int b) {
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }
    private void reverse(int[] nums, int start) {
        int left = start;
        int right = nums.length - 1;
        while(left < right) {
            swap(nums, left, right);
            left++;
            right--;
        }
    }
}
  • 反思:我没有想到保证字典序的含义,要保证最小的操作,这道题想告诉我的是如何维护一个字典序,我没有想明白为什么最后要倒置,其实就是为了保证最小变动,字典序只能大一阶,所以要倒置

287.寻找重复数

关键信息一句话总结:

抽象为用Floyid环算法寻找环的入口

  • 分析:这与我们之前的链表的判断环有何区别,这里的数组的value指向的是下一个节点的index,也就是 slow = nums[slow] 对应 slow = slow.next,fast = nums[nums[fast]] 对应 fast = fast.next.next
java 复制代码
class Solution {
    public int findDuplicate(int[] nums) {
        // 抽象成寻找环的入口
        // 数组的value指向下一节点的index
        int slow = nums[0];
        int fast = nums[0];
        // 1.找到相遇点
        while(true) {
            slow = nums[slow];
            fast = nums[nums[fast]];
            if(slow == fast) {
                break;
            }
        }
        // 2.找入口
        int head = nums[0];
        while(slow != head) {
            head = nums[head];
            slow = nums[slow];
        }
        return head;
    }
}
  • 反思:我没有想到能够抽象成一个环
相关推荐
荣光属于凯撒1 小时前
P15755 [JAG 2025 Summer Camp #1] JAG Box
c++·算法·贪心算法
2301_803554521 小时前
单例模式以及面试可能问的--精写
单例模式·面试·职场和发展
郝学胜-神的一滴1 小时前
CMake:解锁C++跨平台工程构建的核心密钥
开发语言·c++·职场和发展
AI科技星2 小时前
基于v≡c空间光速螺旋量子几何归一化统一场论第一性原理的时间势差本源理论
人工智能·线性代数·算法·机器学习·平面
云泽8082 小时前
蓝桥杯算法精讲:哈夫曼编码的贪心思想与落地实现
算法·职场和发展·蓝桥杯
x_xbx2 小时前
LeetCode:53. 最大子数组和
算法·leetcode·职场和发展
菜菜小狗的学习笔记2 小时前
剑指Offer算法题(一)数组与矩阵
线性代数·算法·矩阵
仰泳的熊猫2 小时前
题目2269:蓝桥杯2016年第七届真题-冰雹数
开发语言·数据结构·c++·算法·蓝桥杯
冷徹 .2 小时前
2023ICPC山东省赛
c++·算法