LeetCode详解C++版

打算把LeetCode上面的题都实现一遍,每日两题

1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。

示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]

思路
巧用map结构
代码

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> hamap;
        int x = -1;
        for (int i = 0; i < nums.size(); i++)
        {
            x = target - nums[i];
            if (hamap.find(x) != hamap.end())
            {
                return{ hamap.find(x)->second, i };
            }
            hamap[nums[i]] = i;
        }
        return {};
    }
};

2. 两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
在这里插入图片描述
思路

代码

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
		ListNode* sumnode = new ListNode(-1);
        ListNode* head = sumnode;
        int sum=0;
        bool carry=false;
        while(l1!=NULL || l2!=NULL)
        {
            sum = 0;
            if(l1!=NULL)
            {
                sum += l1->val;
                l1 = l1->next;
                
            }
            if(l2!=NULL)
            {
                sum += l2->val;
                l2 = l2->next;
            }
            if(carry)
            {
                sum++;
            }
            head->next = new ListNode(sum%10);
            head = head->next;
            if(sum >= 10){
                carry = true;
            }else{
                carry = false;
            }
        }
        if(sum >= 10){
           head->next = new ListNode(1);
        }
        return sumnode->next;
    
    }
};

改进版

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
		ListNode* re = new ListNode(0);
        ListNode* r = re;
        int carry=0;
        while(l1!=NULL || l2!=NULL)
        {
            int x = 0;
            int y = 0;
            if(l1!=NULL)
            {
                x = l1->val;    
            }else{
                x = 0;
            }
            if(l2!=NULL)
            {
                y = l2->val;      
            }else{
                y = 0;
            }
            int s = carry + x + y;
            carry = s/10;
            r->next = new ListNode(s%10);
            r = r->next;
            if(l1!=NULL)
            {
                l1 = l1->next;
            }
            if(l2!=NULL)
            {
                l2 = l2->next;
            }        
        }
        if(carry > 0){
           r->next = new ListNode(1);
        }
        return re->next;
    }
};

11. 盛最多水的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。

示例 1:
输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1]
输出:1

思路
使用双指针 注意!我们每次只要移动高度小的一边,因为移动小的那一边可能会增大,但是移动大的一边一定会减小
代码

class Solution {
public:
    int maxArea(vector<int>& height) {
        int i = 0,j = height.size()-1,res = 0;
        while(i < j){
            if(height[i]<height[j])
            {
                res = max(res,height[i]*(j-i));
                i++;
            }else{
                res = max(res,height[j]*(j-i));
                j--;
            }
           
        }
        return res;
    }
};

15.三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]

思路
可以使用双指针,先排序(时间复杂度nlogn),然后令L = i+1 ,R = n - 1,我们遍历i,如果值大了我们就R–,小了就L++
代码

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ans;
        if(nums.size()<3) return ans;
        sort(nums.begin(), nums.end());
        if(nums[0]>0) return ans;
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i]>0) return ans;
            if(i>0 && nums[i] == nums[i-1]) continue;     
            int left = i+1, right = nums.size()-1;
            while(left< right){
                if(nums[i] + nums[left] + nums[right] == 0)
                {
                    ans.push_back({nums[i], nums[left], nums[right]});
                    while(left<right && nums[left] == nums[left+1])
                        left++;
                    while(left<right && nums[right] == nums[right-1])
                        right--;
                    left++;
                    right--;
                }else if(nums[i] + nums[left] + nums[right] > 0) right--;
                else left++;
            }    
        }
        return ans;
    }
};

33.搜索旋转排序数组

整数数组 nums 按升序排列,数组中的值 互不相同 。

在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

示例 1:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
示例 2:
输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
示例 3:
输入:nums = [1], target = 0
输出:-1

思路
二分查找题,先用二分查找找到k,然后找到目标值
代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
        if(nums.empty()) return -1;
        int n = nums.size(),r = n-1,l = 0;
        // find k
        while(l<r)
        {
            int m = l + (r -l)/2;
            if(nums[m] < nums[r]) r = m;
            else l = m+1;
        }
        int k = l;
        l = 0;
        r = k-1;
        while(l<r)
        {
            int m = l + (r -l)/2;
            if(nums[m] >= target) r = m;
            else l = m+1;
        }
        if(nums[l] == target) return l;
        l = k;
        r = n-1;
        while(l<r)
        {
            int m = l + (r -l)/2;
            if(nums[m] >= target) r = m;
            else l = m+1;
        }
        if(nums[l] == target) return l;
        return -1;
    }
};

34. 在排序数组中查找元素的第一个和最后一个位置

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:
你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?

示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0
输出:[-1,-1]

思路
两分查找,先找开始的位置,在找结束的位置。
代码

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> res(2,-1);
        if(nums.empty()) return res;
        int n = nums.size(),l = 0, r = n-1;
        while(l < r)
        {
            int m = l + (r - l)/2;
            if(nums[m] >= target){
                r = m;
            }else
            {
                l = m + 1;
            }
        }
        if(nums[l] != target) return res;
        res[0] = l;
        r = n;
        while(l < r)
        {
            int m = l + (r - l)/2;
            if(nums[m] <= target){
                l = m + 1;
            }else
            {
                r = m;
            }
        }
        res[1] = l - 1;
        return res;
    }
};

35.搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。

示例 1:
输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:
输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:
输入: nums = [1,3,5,6], target = 7
输出: 4

示例 4:
输入: nums = [1,3,5,6], target = 0
输出: 0

示例 5:
输入: nums = [1], target = 0
输出: 0

思路

代码

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        while(left <= right)
        {
            int mid = left + (right - left)/2;
            if(nums[mid] < target)
            {
                left = mid + 1;
            }
            else 
            {
                right = mid - 1;
            }
        }
        return left;
    }
};

53.最大子数组和

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。

示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [5,4,-1,7,8]
输出:23

思路
可以使用动态规划的方法,如下代码,f_n表示前n个之和最大值
代码

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if(nums.size() == 0) return NULL;
        int res = INT_MIN;
        int f_n = -1;
        for(int i = 0; i < nums.size(); ++i){
            f_n = max(nums[i], f_n + nums[i]);
            res = max(f_n, res);
        }
        return res;
    }
};

64. 最小路径和

给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
在这里插入图片描述
思路

代码

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int m = grid.size();
        int n = grid[0].size();
        if(m <= 0 || n <= 0){
            return 0;
        }
        int dp[m][n];
        dp[0][0] = grid[0][0];
        for(int i = 1;i < m;i++){
            dp[i][0] = grid[i][0] + dp[i-1][0];
        }
        for(int i = 1;i < n;i++){
            dp[0][i] = grid[0][i] + dp[0][i-1]; 
        }
        for(int i = 1;i < m;i++){
            for(int j = 1;j < n;j++){
                dp[i][j] = min(dp[i-1][j],dp[i][j-1]) + grid[i][j];
            }
        }
        return dp[m-1][n-1];
    
    }
};

70.爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。

示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1+ 12.  2 阶

示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1+ 1+ 12.  1+ 23.  2+ 1

思路

代码

class Solution {
public:
    int climbStairs(int n) {
        int a[n+1];
        if(n <= 2){
            return n;
        }
        a[0] = 0;
        a[1] = 1;
        a[2] = 2;
        for(int i = 3;i <= n;i++){
            a[i] = a[i-1] + a[i-2];
        }
        return a[n];
    }
};

74.搜索二维矩阵

编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。
在这里插入图片描述
思路
将二维排序成一维来做,继续用二分查找
代码

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int n = matrix.size(), m = matrix[0].size();
        int l = 0,r = n*m-1;
        while(l<r){
            int mid = l + (r - l)/2;
            int mid1 = mid/m,mid2 = mid%m;
            if(matrix[mid1][mid2] >= target) r = mid;
            else l = mid + 1;
        }
        int ma1 = l/m,ma2 = l%m;
        if(matrix[ma1][ma2] == target) return true;
        return false;

        
    }
};

82. 删除排序链表中的重复元素 II

给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。
在这里插入图片描述
思路
很容易的题,主要是第一个值的话怎么删,我们可以新建一个next 为列表的头head
代码

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if(head == NULL || head->next == NULL) return head;
        ListNode* tem = new ListNode(0, head);
        ListNode* cur = tem;
        while (cur->next && cur->next->next) {
            if (cur->next->val == cur->next->next->val) {
                int x = cur->next->val;
                while (cur->next && cur->next->val == x) {
                    cur->next = cur->next->next;
                }
            }
            else {
                cur = cur->next;
            }
        }

        return tem->next;
    }
};

88. 合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3][2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1][] 。
合并结果是 [1] 。
示例 3:
输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [][1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

思路
我们巧用nums1的结构,把从大到小排序放进去
代码

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int last = m+n-1;
        while(n){
            if(m==0||nums1[m-1]<=nums2[n-1]){
                nums1[last--]=nums2[--n];
            }else{
                nums1[last--]=nums1[--m];
            }
        }
    }
};

153. 寻找旋转排序数组中的最小值

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

示例 1:
输入:nums = [3,4,5,1,2]
输出:1
解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。
示例 2:
输入:nums = [4,5,6,7,0,1,2]
输出:0
解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。
示例 3:
输入:nums = [11,13,15,17]
输出:11
解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。

思路
查找旋转次数就好了
代码

class Solution {
public:
    int findMin(vector<int>& nums) {
        if(nums.empty()) return -1;
        int n = nums.size(),r = n-1,l = 0;
        // find k 旋转次数
        while(l<r)
        {
            int m = l + (r -l)/2;
            if(nums[m] < nums[r]) r = m;
            else l = m+1;
        }
        return nums[l];
    }
};

162. 寻找峰值

峰值元素是指其值严格大于左右相邻值的元素。
给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞ 。
你必须实现时间复杂度为 O(log n) 的算法来解决此问题。

示例 1:
输入:nums = [1,2,3,1]
输出:2
解释:3 是峰值元素,你的函数应该返回其索引 2。
示例 2:
输入:nums = [1,2,1,3,5,6,4]
输出:15 
解释:你的函数可以返回索引 1,其峰值元素为 2;
     或者返回索引 5, 其峰值元素为 6

思路
二分法,只需要判断nums[m] > nums[m+1],因为大的值一定有解
代码

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int n = nums.size(),r = n-1,l = 0;
        while(l<r)
        {
            int m = l + (r - l)/2;
            if(nums[m] > nums[m+1]) r = m;
            else l = m+1;
        }
        return l;
    }
};

167. 两数之和 II - 输入有序数组

给定一个已按照 非递减顺序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。
你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

示例 1:
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:27 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

示例 2:
输入:numbers = [2,3,4], target = 6
输出:[1,3]

示例 3:
输入:numbers = [-1,0], target = -1
输出:[1,2]

思路

代码

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int l = 0;
        int r = numbers.size() - 1;
        while(l<r){
            if(numbers[l]+numbers[r]>target){
                r--;
            }else if(numbers[l]+numbers[r]<target){
                l++;
            }else{
                return {l+1,r+1};
            }
        }
        return {l+1,r+1};
    }
};

189.轮转数组

给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1: [7,1,2,3,4,5,6]
向右轮转 2: [6,7,1,2,3,4,5]
向右轮转 3: [5,6,7,1,2,3,4]

示例 2:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释: 
向右轮转 1: [99,-1,-100,3]
向右轮转 2: [3,99,-1,-100]

思路

代码

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int n = nums.size();
        k = k % n;
        int count = gcd(k, n);
        for (int start = 0; start < count; ++start) {
            int current = start;
            int prev = nums[start];
            do {
                int next = (current + k) % n;
                swap(nums[next], prev);
                current = next;
            } while (start != current);
        }
    }
};

217.存在重复元素

给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。

示例 1:
输入:nums = [1,2,3,1]
输出:true
示例 2:
输入:nums = [1,2,3,4]
输出:false
示例 3:
输入:nums = [1,1,1,3,3,4,3,2,4,2]
输出:true

思路
利用集合的唯一性来做。(暴力穷举算法复杂度太大了 O ( n 2 ) O(n^2) O(n2)
代码

class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        unordered_set<int> s;
        for (int x: nums) {
            if (s.find(x) != s.end()) {
                return true;
            }
            s.insert(x);
        }
        return false;
    }
};

278.第一个错误的版本

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

示例 1:
输入:n = 5, bad = 4
输出:4
解释:
调用 isBadVersion(3) -> false 
调用 isBadVersion(5) -> true 
调用 isBadVersion(4) -> true
所以,4 是第一个错误的版本。

示例 2:
输入:n = 1, bad = 1
输出:1

思路

代码

class Solution {
public:
    int firstBadVersion(int n) {
       int l = 1, r = n, m = 0;        
        while (l<r){
            m = l + ((r - l) >> 1);
            if(isBadVersion(m))
                r = m;
            else
                l = m + 1;
        }         
        return l;

    }
};

283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

思路

代码

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int m = nums.size(),j = 0;
        
        for(int i = 0;i < m;i++){
            if(nums[i]!=0)
            {
                nums[j++] = nums[i];
                
            }
        }
        for(int i = j;j < m;j++)
        {
            nums[j] = 0;
        }
        
    }
};

344. 反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

示例 1:
输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]

示例 2:
输入:s = ["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]

思路

代码

class Solution {
public:
    void reverseString(vector<char>& s) {   
        int r = s.size();
        int l = r;
        for(int i = 0; i<r/2;i++){
            l--;
            char tmp = s[i];
            s[i] = s[l];
            s[l] = tmp;
        }

    }
};

一行实现

class Solution {
public:
    void reverseString(vector<char>& s) {   
        s.reverse()
    }
};

557. 反转字符串中的单词 III

给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

示例:
输入:"Let's take LeetCode contest"
输出:"s'teL ekat edoCteeL tsetnoc"

思路

代码

class Solution {
public:
    string reverseWords(string s) {
        int n=s.size();
        int begin=0,end;
        for(int i=0;i<n+1;i++)
        {
           if(s[i]==' '||s[i]=='\0')
           {
               for(end=i-1;begin<end;begin++,end--)
               {
                   swap(s[begin],s[end]);
               }
               begin=i+1;
           }
        }
        
        return s;
    }
};

704. 二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

思路

代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
       int left = 0;
       int right = nums.size() - 1;
       
       while(left <= right)
       {
           int mid = left + (right - left)/2;
           if(nums[mid] < target)
           {
                left = mid + 1;
           }
            else if(nums[mid] > target){
                right = mid - 1;
            }
            else{
                return mid;
            }   
       }
            
        return -1;
    }
};

844. 比较含退格的字符串

给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。
注意:如果对空文本输入退格字符,文本继续为空。

示例 1:
输入:s = "ab#c", t = "ad#c"
输出:true
解释:s 和 t 都会变成 "ac"。
示例 2:
输入:s = "ab##", t = "c#d#"
输出:true
解释:s 和 t 都会变成 ""。
示例 3:
输入:s = "a#c", t = "b"
输出:false
解释:s 会变成 "c",但 t 仍然是 "b"

思路
如果暴力的话肯定不行的,要占用新的内存,且要比较。我们可以使用双指针,从后往前读,比较每一个字符。有不符号返回flase
代码

class Solution {
public:
    bool backspaceCompare(string s, string t) {
       int i = s.size() - 1, j = t.size() - 1;
        int skipS = 0, skipT = 0;

        while (i >= 0 || j >= 0) {
            while (i >= 0) {
                if (s[i] == '#') {
                    skipS++, i--;
                } else if (skipS > 0) {
                    skipS--, i--;
                } else {
                    break;
                }
            }
            while (j >= 0) {
                if (t[j] == '#') {
                    skipT++, j--;
                } else if (skipT > 0) {
                    skipT--, j--;
                } else {
                    break;
                }
            }
            if (i >= 0 && j >= 0) {
                if (s[i] != t[j]) {
                    return false;
                }
            } else {
                if (i >= 0 || j >= 0) {
                    return false;
                }
            }
            i--, j--;
        }
        return true;
    
    }
};

977. 有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums,返回每个数字的平方 组成的新数组,要求也按非递减顺序排序。

示例 1:

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

示例 2:
输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]

提示:
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums 已按 非递减顺序 排序

进阶:
请你设计时间复杂度为 O(n) 的算法解决本问题

思路

代码

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        for(int i=0;i<nums.size();i++)
        {
            nums[i] = nums[i]*nums[i];
            
        }
        sort(nums.begin(),nums.end());
        return nums;
    }
};

986. 区间列表的交集

给定两个由一些 闭区间 组成的列表,firstList 和 secondList ,其中 firstList[i] = [starti, endi] 而 secondList[j] = [startj, endj] 。每个区间列表都是成对 不相交 的,并且 已经排序 。
返回这 两个区间列表的交集 。
形式上,闭区间 [a, b](其中 a <= b)表示实数 x 的集合,而 a <= x <= b 。
两个闭区间的 交集 是一组实数,要么为空集,要么为闭区间。例如,[1, 3] 和 [2, 4] 的交集为 [2, 3] 。

示例 1:
输入:firstList = [[0,2],[5,10],[13,23],[24,25]], secondList = [[1,5],[8,12],[15,24],[25,26]]
输出:[[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]
示例 2:
输入:firstList = [[1,3],[5,9]], secondList = []
输出:[]
示例 3:
输入:firstList = [], secondList = [[4,8],[10,12]]
输出:[]
示例 4:
输入:firstList = [[1,7]], secondList = [[3,10]]
输出:[[3,7]]

思路
使用双指针,一个指向其中一个数组,对每一个内部数组进行比较。
代码

class Solution {
public:
    vector<vector<int>> intervalIntersection(vector<vector<int>>& firstList, vector<vector<int>>& secondList) {
        vector<vector<int>> res;
        if(firstList.empty()||secondList.empty()) return res;
        int i = 0,j = 0;
        while(i < firstList.size() && j < secondList.size())
        {
            int start = max(firstList[i][0],secondList[j][0]);
            int end  = min(firstList[i][1],secondList[j][1]);
            if(start <= end) res.push_back({start,end});
            if(firstList[i][1] < secondList[j][1]) i++;
            else j++;
        }
        return res;
    }
};

剑指 Offer 05. 替换空格

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

示例 1:
输入:s = "We are happy."
输出:"We%20are%20happy."

思路

代码

class Solution {
public:
    string replaceSpace(string s) {
        int count = 0; // 统计空格的个数
        int sOldSize = s.size();
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == ' ') {
                count++;
            }
        }
        // 扩充字符串s的大小,也就是每个空格替换成"%20"之后的大小
        s.resize(s.size() + count * 2);
        int sNewSize = s.size();
        // 从后先前将空格替换为"%20"
        for (int i = sNewSize - 1, j = sOldSize - 1; j < i; i--, j--) {
            if (s[j] != ' ') {
                s[i] = s[j];
            } else {
                s[i] = '0';
                s[i - 1] = '2';
                s[i - 2] = '%';
                i -= 2;
            }
        }
        return s;
    }
};

剑指 Offer 06. 从尾到头打印链表

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

示例 1:
输入:head = [1,3,2]
输出:[2,3,1]

思路

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> reversePrint(ListNode* head) {
        vector<int> res;

        while(head)
        {
            res.push_back(head->val);
            head=head->next;
        }

        reverse(res.begin(),res.end());

        return res;
    }
};

剑指 Offer 09.用两个栈实现队列

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
思路

代码

class CQueue {
public:
    stack<int>s1;
    stack<int>s2;
    CQueue() {

    }
    
    void appendTail(int value) {
        s1.push(value);
    }
    
    int deleteHead() {
        if(s1.empty() && s2.empty())
        {
            return -1;
        }
        if(!s1.empty() && s2.empty())
        {
            while(!s1.empty())
            {
                s2.push(s1.top());
                s1.pop();
            }
            int temp = s2.top();
            s2.pop();
            return temp;
        }
        if(!s2.empty())
        {
            int temp = s2.top();
            s2.pop();
            return temp;
        }
        return -1;
    }
};

/**
 * Your CQueue object will be instantiated and called as such:
 * CQueue* obj = new CQueue();
 * obj->appendTail(value);
 * int param_2 = obj->deleteHead();
 */

剑指 Offer 24. 反转链表

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

思路

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        vector<int> res;
        ListNode *p= head;
        ListNode *q = head; 
        while(p)
        {
            res.push_back(p->val);
            p=p->next;
        }

        reverse(res.begin(),res.end());
        
        for(int i = 0;i < res.size();i++)
        {    
            q->val = res[i];
            q = q->next; 
        }
        return head;
    }
};

剑指 Offer 30.包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
思路

代码

class MinStack {
public:
    /** initialize your data structure here. */
    int Min=inf;
    stack<int> st;
    MinStack() {

    }
    
    void push(int x) {
        st.push(Min);
        if(x<Min) Min=x;
        st.push(x);
    }
    
    void pop() {
        st.pop();
        Min = st.top();
        st.pop();
    }
    
    int top() {
        return st.top();
    }
    
    int min() {
        return Min;
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(x);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->min();
 */
  • 12
    点赞
  • 96
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值