Hot100 技巧 相关题目总结

136. 只出现一次的数字

题目

Given a non-empty array of integers nums, every element appears twice except for one. Find that single one.
You must implement a solution with a linear runtime complexity and use only constant extra space.

示例

Input: nums = [2,2,1]
Output: 1

思路

这道题主要考察对异或的理解

异或也叫半加运算,其运算法则相当于不带进位的二进制加法:二进制下用1表示真,0表示假,则异或的运> 算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1),这些法则与加法是相同的,只是不带进位,所以异或常被认作不进位加法

比如说3 ^ 5=6:

011 = 3
101 = 5
----------
110 = 6

需要注意的是,异或有以下两个性质:

  1. 任何数与自己进行异或操作,结果都是0
  2. 任何数与0进行异或操作,数值都不会改变,比如说:3^0=3

这就意味着:

  1. 先声明一个变量result=0
  2. 使用result依次和数组中的每个元素进行异或操作
  3. 最后result的值就是数组中只出现一次的数字的值
  4. 所以返回result即可

代码

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int result{};
        for (auto num : nums) {
            result ^= num;
        }
        return result;
    }
};

169. 多数元素

题目

Given an array nums of size n, return the majority element.
The majority element is the element that appears more than ⌊n / 2⌋ times. You may assume that the majority element always exists in the array.

示例

Input: nums = [3,2,3]
Output: 3

思路

可以把不同数字想象不同阵营的士兵,他们都急于抢占高地,而由于数组中有一个元素的个数是大于 ⌊ n / 2 ⌋ \lfloor n/2 \rfloor n/2 的,那么最后肯定是这个多数元素抢占到高地,返回这个元素即可

代码

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int cur = nums[0];
        int times = 1;
        for (int i = 1; i < nums.size(); ++i) {
            if (cur == nums[i]) {
                times++;
            } else {
                times--;
                if (times == 0) {
                    times = 1;
                    cur = nums[i];
                }
            }
        }
        return cur;
    }
};

75. 颜色分类

题目

Given an array nums with n objects colored red, white, or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white, and blue.
We will use the integers 0, 1, and 2 to represent the color red, white, and blue, respectively.
You must solve this problem without using the library’s sort function.

示例

Input: nums = [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]

思路

定义三个分割点left,mid,right

其中:

[ 0 , l e f t ) ∈ 0 [ l e f t , m i d ] ∈ 1 ( r i g h t , n u m s . s i z e ( ) − 1 ] ∈ 2 [0, left) \in 0 \\ [left, mid] \in 1 \\ (right, nums.size() - 1] \in 2 [0,left)0[left,mid]1(right,nums.size()1]2

代码

class Solution {
public:
    void sortColors(vector<int>& nums) {
        int left = 0;
        int mid = 0;
        int right = nums.size() - 1;
        while (mid <= right) {
            if (nums[mid] == 1) {
                mid++;
            } else if (nums[mid] == 0) {
                swap(nums[left], nums[mid]);
                left++;
                mid++;
            } else {
                swap(nums[mid], nums[right]);
                right--;
            }
        }    
    }
};

31. 下一个排列

题目

A permutation of an array of integers is an arrangement of its members into a sequence or linear order.

For example, for arr = [1,2,3], the following are all the permutations of arr: [1,2,3], [1,3,2], [2, 1, 3], [2, 3, 1], [3,1,2], [3,2,1].
The next permutation of an array of integers is the next lexicographically greater permutation of its integer. More formally, if all the permutations of the array are sorted in one container according to their lexicographical order, then the next permutation of that array is the permutation that follows it in the sorted container. If such arrangement is not possible, the array must be rearranged as the lowest possible order (i.e., sorted in ascending order).

For example, the next permutation of arr = [1,2,3] is [1,3,2].
Similarly, the next permutation of arr = [2,3,1] is [3,1,2].
While the next permutation of arr = [3,2,1] is [1,2,3] because [3,2,1] does not have a lexicographical larger rearrangement.
Given an array of integers nums, find the next permutation of nums.

The replacement must be in place and use only constant extra memory.

示例

Input: nums = [1,2,3]
Output: [1,3,2]

思路

  1. 从后往前遍历,如果前一个数比当前数大,则继续遍历;否则停止。比如说,对于数字 13456987,最后会遍历到数字9这个地方
  2. 还是从后往前遍历,找到第一个比终止点前一个数大的数,交换这两个数。比如说,对于数字13456987,数字7和数字6进行交换,变为13457986
  3. 翻转终止点及终止点后的数。比如说,对于数字13456987,经过第二步操作变为了13457986,再进行翻转,结果为13457689
  4. 最终结果就是下一个排列数,直接返回即可

特殊情况

如果没找到终止点(即数字呈递增状态,如12345),直接翻转数字整体即可(12345变为54321

代码

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int mid = nums.size() - 1;
        while (mid > 0) {
            if (nums[mid] > nums[mid-1]) {
                break;
            }
            mid--;
        }

        if (mid == 0) {
            reverse(nums.begin(), nums.end());
            return;
        }

        int swap_idx = nums.size() - 1;
        while (1) {
            if (nums[swap_idx] > nums[mid-1]) {
                swap(nums[swap_idx], nums[mid-1]);
                break;
            }
            swap_idx--;
        }
        reverse(nums.begin()+mid, nums.end());
    }
};

287. 寻找重复数

题目

Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive.
There is only one repeated number in nums, return this repeated number.
You must solve the problem without modifying the array nums and uses only constant extra space.

示例

Input: nums = [1,3,4,2,2]
Output: 2

思路

Keypoint: 快慢指针

这道题对数据进行的限制:

  1. 数组有n+1个元素,这意味着数组的下标范围是[0, n]
  2. 每个元素的数值范围是[1,n],这意味着:数组中的每个元素都能当作下标,来索引另一个元素
  3. 只有一个重复的元素,这意味着:以数组下标来构造一个链表,节点的下一个节点即为当前数组下标对应的元素,这个链表一定是有环的,且环的起始点的下标的数值一定等于这个重复的元素

比如说,对于数组[1,3,4,2,2],可以构建这么一个图:

               -----------
               |         |
0 -> 1 -> 3 -> 2 ----->  4

那么使用Hot100 链表 相关题目总结中142题的做法即可找到这个数了

代码

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int slow = 0;
        int fast = 0;

        while (1) {
            slow = nums[slow];
            fast = nums[nums[fast]];
            if (slow == fast) {
                break;
            }
        }

        slow = 0;
        while (slow != fast) {
            slow = nums[slow];
            fast = nums[fast];
        }

        int result = slow;
        return result;
    }
};
  • 23
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值