leetcode hot 100 刷题记录(easy)

题目300:最长递增子序列(NO)

  • 解题思路:动态规划,就是dp[i]的运用,这里dp[i]表示第i个元素为结尾的最长子序列。

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的
子序列。

class Solution 
{
public:
    int lengthOfLIS(vector<int>& nums) 
    {
        int n = nums.size();
        if (n == 0) 
        {
            return 0;
        }
        vector<int> dp(n, 0);
        int max_count=0;
        for (int i = 0; i < n; ++i) 
        {
            dp[i] = 1;//如果前面没有比他小的了,那自己本身就是一个最长子序列
            for (int j = 0; j < i; ++j) 
            {
                if (nums[j] < nums[i]) 
                {
                    //这里是每次扫描前面就记录最大的dp[i]
                    dp[i] = max(dp[i], dp[j] + 1);
                }
            }

            if(dp[i]>max_count)
            {
                max_count=dp[i];
            }        
        }
        return max_count;
    }
};

题目215:数组中的第k个最大元素(NO)

  • 解题思路:使用快速排序算法

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

class Solution {
public:

    void quickSort(std::vector<int>& arr, int left, int right) 
    {
        if (left >= right) 
        {
            return;
        }

        int pivot = arr[(left + right) / 2];
        int i = left, j = right;

        //这次一扫描,就会将整个数组划分为两个区域,以pivot为分界线
        while (i <= j) 
        {
            while (arr[i] < pivot) 
            {
                //找到比中间结点大的
                i++;
            }
            while (arr[j] > pivot) 
            {
                //找到比中间结点小的
                j--;
            }
            if (i <= j) 
            {
                //交换两个元素
                swap(arr[i], arr[j]);
                i++;
                j--;
            }
        }

        //检查左边
        if (left < j) 
        {
            quickSort(arr, left, j);
        }

        //检查右边
        if (i < right) 
        {
            quickSort(arr, i, right);
        }
    }
    int findKthLargest(vector<int>& nums, int k) {
        int len=nums.size();
        quickSort(nums,0,len-1);
        return nums[len-k];
    }
};

题目1:两数之和(YES)

  • 解题思路:使用哈希表

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        //使用哈希表
        unordered_map<int,int>map;

        for(int i=0;i<nums.size();i++)
        {
            if(map.find(target-nums[i])!=map.end())
            {
                return {i,map[target-nums[i]]};
            }
            map[nums[i]]=i;
            
        }
        return {};
    }
};

题目3:无重复字符的最长子串(NO)

  • 解题思路:使用滑动窗口,就是和unordered_set搭配使用,用set来检查是否重复,没有重复在继续添加,如果重复了就删除掉第一个,因为是for一次遍历,所以每个i都可以成为第一个子串。

给定一个字符串 s ,请你找出其中不含有重复字符的 最长
子串的长度。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        //使用滑动窗口的方法,就是配合unordered_set来实现
        //用set来判断是否出现了重复的字符,如果重复了就删除第一个,否则没重复的话
        //就继续在set中添加字符

        unordered_set<char>set;
        int ans=0;
        int temp=-1;
        int len=s.size();

        for(int i=0;i<s.size();i++)
        {
            //第一个字符是不用删除的
            if(i!=0)
            {
                //删除第一个元素
                set.erase(s[i-1]);
            }

            //以i为起点一直添加元素
            //确保下一个位置合法才能够加入
            while(temp+1<len&&!set.count(s[temp+1]))
            {
                set.insert(s[temp+1]);
                temp++;
            }

            //说明遇到了重复的字符,保存这次的子串长度
            ans=max(ans,temp-i+1);
        }

        return ans;
    }
};

题目11:盛最多水的容器(YES)

  • 解题思路:最刚开始第一想到的是使用双重for遍历一遍,让每个i都作为第一条边,每个的最大的面积,但是显然这样时间复杂度太高了。

  • 错误示例

class Solution {
public:
    int maxArea(vector<int>& height) {
        //我现在突然想到的是使用双重for遍历,每个i都可以当容器的第一个位置
        //然后找到其中最大的

        int max_ans=0;
        for(int i=0;i<height.size();i++)
        {
            for(int j=i+1;j<height.size();j++)
            {
                int area=(j-i)*min(height[i],height[j]);
                max_ans=max(area,max_ans);
            }
        }

        return max_ans;
    }
};

  • 后面我又想到了一个思路,既然是要计算面积,底乘以高,当然是保证底部越长越好,所以在大的情况从两边开始扫描一定不会漏掉。且在靠齐的时候,当然是向边长高的靠齐最好。

  • 正确写法

class Solution {
public:
    int maxArea(vector<int>& height) {
        //此时我又想到了面积的算法是底乘以高,所以底应该尽可能的长,所以直接从两边开始扫描
        //就行了
        int left=0;
        int right=height.size()-1;
        
        int max_area=0;
        while(left<right)
        {
            //从两边开始记录最大面积
            int temp=(right-left)*min(height[right],height[left]);
            if(temp>max_area)
            {
                max_area=temp;
            }

            if(height[left]<height[right])
            {
                //想要面积最大,应该向高的一边靠齐
                left++;
            }else
            {
                right--;
            }
        }

        return max_area;

    }
};

题目70:爬楼梯(YES)

  • 典型的动态规划问题,考察队dp[i]数组的使用,这里dp[i]表示的是到达第i阶楼梯的方法数。这里需要关注的点是第3阶的方法数是第1阶和第2阶方法数的和。

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

class Solution {
public:
    int climbStairs(int n) {
        //这题使用的是动态规划问题
        //dp[i]的含义是到第i阶有多少不同的方法
        vector<int>dp(n+1);
        dp[0]=1;//单纯为了做题而设置的,没意义
        dp[1]=1;

        if(n<2)
        {
            return dp[n];
        }

        for(int i=2;i<=n;i++)
        {
            dp[i]=dp[i-1]+dp[i-2];
        }

        return dp[n];
    }
};

题目146:LRU缓存(NO)

  • 解题思路:使用了双链表和哈希表的结合,这题值得关注。

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

//双向链表
struct DLinkedNode {
    int key, value;
    DLinkedNode* prev;
    DLinkedNode* next;
    DLinkedNode(): key(0), value(0), prev(nullptr), next(nullptr) {}
    DLinkedNode(int _key, int _value): key(_key), value(_value), prev(nullptr), next(nullptr) {}
};

class LRUCache {
private:
    unordered_map<int, DLinkedNode*> cache;
    DLinkedNode* head;
    DLinkedNode* tail;
    int size;
    int capacity;

public:
    LRUCache(int _capacity): capacity(_capacity), size(0) {
        // 使用伪头部和伪尾部节点
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head->next = tail;
        tail->prev = head;
    }
    
    int get(int key) {
        if (!cache.count(key)) {
            return -1;
        }
        // 如果 key 存在,先通过哈希表定位,再移到头部
        DLinkedNode* node = cache[key];
        moveToHead(node);
        return node->value;
    }
    
    void put(int key, int value) {
        if (!cache.count(key)) {
            // 如果 key 不存在,创建一个新的节点
            DLinkedNode* node = new DLinkedNode(key, value);
            // 添加进哈希表
            cache[key] = node;
            // 添加至双向链表的头部
            addToHead(node);
            ++size;
            if (size > capacity) {
                // 如果超出容量,删除双向链表的尾部节点
                DLinkedNode* removed = removeTail();
                // 删除哈希表中对应的项
                cache.erase(removed->key);
                // 防止内存泄漏
                delete removed;
                --size;
            }
        }
        else {
            // 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部
            DLinkedNode* node = cache[key];
            node->value = value;
            moveToHead(node);
        }
    }

    void addToHead(DLinkedNode* node) {
        node->prev = head;
        node->next = head->next;
        head->next->prev = node;
        head->next = node;
    }
    
    void removeNode(DLinkedNode* node) {
        node->prev->next = node->next;
        node->next->prev = node->prev;
    }

    void moveToHead(DLinkedNode* node) {
        removeNode(node);
        addToHead(node);
    }

    DLinkedNode* removeTail() {
        DLinkedNode* node = tail->prev;
        removeNode(node);
        return node;
    }
};

题目200:岛屿数量(YES)

  • 解题思路:用双重for遍历所有的元素,第一个进来的1就是一个岛屿,然后用广度优先遍历遍历这个岛屿的1,并使用check数组设置标记为访问过了。这里可以优化的地方就是使用dx[ ]和dy[ ]来控制方向

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
    if(grid.empty()) {
        return 0;
    }

    int row = grid.size();
    int col = grid[0].size();

    //用来标记是否访问过
    vector<vector<bool>> check(row, vector<bool>(col, false));
    int ans = 0;//记录岛屿的数量

    //用来控制方向的   上  下  右 左
    vector<int> dx = {1, -1, 0, 0};
    vector<int> dy = {0, 0, 1, -1};

    //将所有的元素都检查一遍
    for(int i = 0; i < row; i++) 
    {
        for(int j = 0; j < col; j++) 
        {
            if(grid[i][j] == '1' && check[i][j] == false) 
            {
                ans++;//能进来的就是一个岛屿
                queue<pair<int, int>> que;
                que.push({i, j});
                check[i][j] = true;

                while(!que.empty()) 
                {
                    pair<int,int> temp = que.front();
                    que.pop();

                    for(int k = 0; k < 4; k++) 
                    {
                        int x = temp.first + dx[k];
                        int y = temp.second + dy[k];
                        if(x >= 0 && x < row && y >= 0 && y < col && grid[x][y] == '1' && check[x][y] == false) 
                        {
                            que.push({x, y});
                            check[x][y] = true;
                        }
                    }
                }
            }
        }
    }
    return ans;
}
};

题目581:最短无序连续子数组(YES)

  • 这题直接先用快速排序算法加上从left到right进行比较就行。

给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。

请你找出符合题意的 最短 子数组,并输出它的长度。

class Solution {
public:
    //使用快速排序
    void quick_sort(vector<int>&nums,int left,int right)
    {
        //递归跳出条件
        if (left >= right) 
        {
            return;
        }
        //定义中心轴
        int mid=nums[(left+right)/2];

        int j=right;
        int i=left;
        while(i<j)
        {
            while(nums[i]<mid) i++;

            while(nums[j]>mid) j--;

            //判断合法性
            if(i<=j)
            {
                swap(nums[i],nums[j]);
                i++;
                j--;
            }
        }

        //在判断一次左右
        if(left<j)
        {
            quick_sort(nums,left,j);
        }

        if(i<right)
        {
            quick_sort(nums,i,right);
        }
    }

    int findUnsortedSubarray(vector<int>& nums) {
        vector<int>ans=nums;
        quick_sort(nums,0,nums.size()-1);

        int left=0;
        int right=nums.size()-1;
        int len=nums.size();
        while(left<len&&nums[left]==ans[left])
        {
            left++;
        }

        while(right>=0&&nums[right]==ans[right])
        {
            right--;
        }

        if(left>right)
        {
            return 0;
        }
        

        return right-left+1;
    }
};

题目94:二叉树的中序遍历(YES)

  • 解题思路:二叉树中序遍历的算法,这个最容易记了。

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    void inorder(TreeNode*root,vector<int>&ans)
    {
        if(root==nullptr)
        {
            return ;
        }
        inorder(root->left,ans);
        ans.push_back(root->val);
        inorder(root->right,ans);

    }

    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>ans;
        inorder(root,ans);
        return ans;
    }
};

题目155:最小栈(NO)

  • 解题思路:难点在于想不到用另外一个栈来表示最小的元素

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。


class MinStack {
    stack<int> x_stack;
    stack<int> min_stack;
public:
    MinStack() {
        min_stack.push(INT_MAX);
    }
    
    void push(int x) {
        x_stack.push(x);
        min_stack.push(min(min_stack.top(), x));
    }
    
    void pop() {
        x_stack.pop();
        min_stack.pop();
    }
    
    int top() {
        return x_stack.top();
    }
    
    int getMin() {
        return min_stack.top();
    }
};



/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(val);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */
 

题目283:移动零(YES)

  • 解题思路:使用双指针,left用来存储非零元素,right用来扫描非零元素,一旦right找到了,就里面放到left中。

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

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        //用一个left指针来表示非零元素
        int left=0;
        int right=0;

        while(right<nums.size())
        {
            if(nums[right]==0)
            {
                right++;
            }else
            {
                //交换位置
                swap(nums[left],nums[right]);
                right++;
                left++;
            }
        }

        
    }
};

题目101:对称二叉树(YES)

  • 解题思路:使用层序遍历,使用两个队列left_que和right_que两个遍历的顺序不同。分别进行判断。

给你一个二叉树的根节点 root , 检查它是否轴对称。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
   bool isSymmetric(TreeNode* root) {
    if(root == nullptr) {
        return true; // 空树是对称的
    }
    
    queue<TreeNode*> left_que;
    queue<TreeNode*> right_que;
    left_que.push(root->left);
    right_que.push(root->right);

    while(!left_que.empty() && !right_que.empty()) {
        TreeNode* temp_left = left_que.front();
        TreeNode* temp_right = right_que.front();

        left_que.pop();
        right_que.pop();

        //判断不合法条件
        if((temp_left == nullptr && temp_right != nullptr) || 
           (temp_left != nullptr && temp_right == nullptr)) {
            return false;
        } else if(temp_left == nullptr && temp_right == nullptr) {
            continue;
        }

        if(temp_left->val != temp_right->val) {
            return false;
        }

        //即便是空值也要入栈
        left_que.push(temp_left->left);
        left_que.push(temp_left->right);

        right_que.push(temp_right->right);
        right_que.push(temp_right->left);
    }

    if(!left_que.empty() || !right_que.empty()) {
        return false;
    }

    return true;
}
};

题目543:二叉树的直径(NO)

  • 解题思路:深度优先遍历

给你一棵二叉树的根节点,返回该树的 直径 。

二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。

两节点之间路径的 长度 由它们之间边数表示。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
private:
    int ans;
    int depth(TreeNode* rt){
        if (rt == NULL) {
            return 0; // 访问到空节点了,返回0
        }
        int L = depth(rt->left); // 左儿子为根的子树的深度
        int R = depth(rt->right); // 右儿子为根的子树的深度
        ans = max(ans, L + R + 1); // 计算d_node即L+R+1 并更新ans
        return max(L, R) + 1; // 返回该节点为根的子树的深度
    }
public:
    int diameterOfBinaryTree(TreeNode* root) {
        ans = 1;
        depth(root);
        return ans - 1;
    }
};

  • 解析

这段代码实际上是在通过递归的方式来计算二叉树的直径,直径是指二叉树中任意两个节点之间的最长路径的节点数。

在这段代码中,主要使用了两个函数:

depth 函数:这是一个递归函数,用于计算以当前节点为根的子树的深度。在该函数中,首先判断当前节点是否为空,若为空则返回深度 0。然后递归计算左子树和右子树的深度(分别记为L和R),并返回左右子树深度的较大值加上 1(加 1 是因为当前节点也要算在内)。在递归的过程中,还会更新一个全局变量 ans,该变量记录了经过当前节点的路径的节点数之和的最大值。

diameterOfBinaryTree 函数:这是一个公开的函数,用户通过调用这个函数来计算二叉树的直径。在这个函数中,首先初始化变量 ans 为 1,然后调用 depth 函数来计算整棵二叉树的直径。最后返回 ans - 1,因为题目要求的是节点数而非边数。

综上所述,这段代码通过递归的方式遍历二叉树,计算每个节点为根节点的子树的深度,并在递归过程中更新最长路径的节点数。最终得出二叉树的直径。

题目461:汉明距离(NO)

  • 解题思路:通过以为操作来进行判断

两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。

给你两个整数 x 和 y,计算并返回它们之间的汉明距离。

class Solution {
public:
    int hammingDistance(int x, int y) {
        int s = x ^ y, ret = 0;
        while (s) {
            ret += s & 1;
            s >>= 1;
        }
        return ret;
    }
};

这段代码实现了计算两个整数 x 和 y 之间的汉明距离的功能。汉明距离是指两个整数的二进制表示中对应位不同的位数。

在代码中,首先计算两个整数 x 和 y 的按位异或结果,将结果存储在变量 s 中。然后使用一个循环,不断右移变量 s,并在每次循环中获取最右边的位(即获取最低位),如果该位为1则表示在该位置上 x 和 y 的二进制表示不同,累加到返回值 ret 中。最后返回 ret,即 x 和 y 之间的汉明距离。

通过这种方法,代码有效地计算了两个整数之间的汉明距离。

  • 知识点补充

在C++中,右移操作符 >> 对于有符号整数和无符号整数的处理方式是不同的:

对于有符号整数:

如果整数是有符号的(int、short、char等),右移操作会保持符号位不变。即,对于正数,右移时在最高位补0;对于负数,右移时在最高位补1。这种方式称为“带符号右移”。
对于无符号整数:

如果整数是无符号的(unsigned int、unsigned short、unsigned char等),右移操作会在最高位始终补0。这种方式称为“无符号右移”。
在给定的代码中,变量 s 的类型没有特别指定,因此默认情况下会被视为有符号整数。因此,右移操作 s >>= 1 会保持符号位不变,即在右移的过程中,负数的最高位会一直被补1,而不会被移除。因此,右移操作并不会去掉最低位,而是将整个 s 数字向右移动一位,新的最高位会根据原来的符号位进行填充。

题目448:找到数组中消失的数字(YES)

  • 解题思路:使用哈希表记录已有的数字,然后从1开始for遍历一遍。

给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。

class Solution {
public:
    vector<int> findDisappearedNumbers(vector<int>& nums) {
        //使用哈希表来存储
        unordered_map<int,int>map;

        for(int i=0;i<nums.size();i++)
        {
            map[nums[i]]++;
        }
        vector<int>ans;
        for(int i=1;i<=nums.size();i++)
        {
            if(map[i]==0)
            {
                ans.push_back(i);
            }
        }

        return ans;
    }
};

题目141:环形链表(YES)

  • 这题显然使用哈希表是最简单的。

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        //使用哈希表显然是最简单的

        unordered_map<ListNode*,int>map;

        ListNode*temp=head;
        while(temp!=NULL&&!map.count(temp))
        {
            map[temp]++;
            temp=temp->next;
        }

        if(temp==NULL)
        {
            return false;
        }

        return true;
    }
};

题目155:最小栈(NO)

  • 这题要使用两个栈,一个当正常的栈来使用,另外一个用来存放最小的元素。关键的地方是刚开是最小栈要放置INT_MAX,后面每次和放进的元素进行比较,放入最小的。

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。

 class MinStack {
public:

    //这道题使用两个栈
    stack<int>s1;//这里用来正常使用栈的功能
    stack<int>min_s2;//这里用用来放置最小的元素

    int num_min;

    MinStack() {
        num_min=INT_MAX;
        min_s2.push(num_min);
    }
    
    void push(int val) {
        s1.push(val);

        //将最小元素入栈
        min_s2.push(min(min_s2.top(),val));
    }
    
    void pop() {
        s1.pop();
        min_s2.pop();
    }
    
    int top() {
        return s1.top();
    }
    
    int getMin() {
        return min_s2.top();
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(val);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */

题目226:翻转二叉树(YES)

  • 解题思路:使用层序遍历每一个节点,并交换它的左右孩子节点。

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root==nullptr)
        {
            return root;
        }
        //使用层序遍历每个节点,并交换左右节点
        queue<TreeNode*>que;
        que.push(root);

        while(!que.empty())
        {
            int size=que.size();
            for(int i=0;i<size;i++)
            {
                TreeNode*current=que.front();
                que.pop();
                TreeNode*current_left=current->left;
                TreeNode*current_right=current->right;

                //交换节点
                current->left=current_right;
                current->right=current_left;

                if(current->left!=nullptr)
                {
                    que.push(current->left);
                }

                if(current->right!=nullptr)
                {
                    que.push(current->right);
                }

            }
        }

        return root;

    }
};

题目234:回文链表(YES)

  • 解题思路:使用数组来存储链表的数据,最后判断数组是否对称就行。

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

/**
 * 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:
    bool isPalindrome(ListNode* head) {
        //先使用最简单的方法来解决,使用数组的存储一遍链表的数据
        vector<int>ans;
        ListNode*temp=head;

        while(temp!=nullptr)
        {
            ans.push_back(temp->val);
            temp=temp->next;
        }

        //检查ans是否对称
        int j=ans.size()-1;
        int i=0;

        while(i<j)
        {
            if(ans[i]==ans[j])
            {
                i++;
                j--;
            }else
            {
                return false;
            }
        }

        return true;
    }
};

题目617:合并二叉树(NO)

  • 解题思路:这题递归的方法并不好想,暂时先记住解题思路吧。

给你两棵二叉树: root1 和 root2 。

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if (t1 == nullptr) {
            return t2;
        }
        if (t2 == nullptr) {
            return t1;
        }
        auto merged = new TreeNode(t1->val + t2->val);
        merged->left = mergeTrees(t1->left, t2->left);
        merged->right = mergeTrees(t1->right, t2->right);
        return merged;
    }
};

题目415:字符串相加(NO)

  • 解题思路:就使用模拟的方法,从最低位开始相加,主要需要注意的是char转成int是'1'-'0'=1
  • int 转成 char是1+'0'='1'

给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。

你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。

class Solution {
public:
    string addStrings(string num1, string num2) {
        int num1_size = num1.size() - 1;  
        int num2_size = num2.size() - 1;  

        // 确保 ans 初始化为空字符串  
        string ans;  
        int count = 0; // 进位位  
        int i = 0;     // 结果字符串的索引  

        while (num1_size >= 0 || num2_size >= 0 || count > 0) 
        {  
            int num1_num = (num1_size >= 0) ? (num1[num1_size] - '0') : 0;  
            int num2_num = (num2_size >= 0) ? (num2[num2_size] - '0') : 0;  

            // 计算当前位的和  
            int sum = num1_num + num2_num + count;  
            count = sum / 10; // 更新进位  
            ans.insert(ans.begin(), (sum % 10) + '0'); // 把当前位的结果插入ans 的开头  

            num1_size--;  
            num2_size--;  
        }  

     
        return ans; 

    }
};

题目14:最长公共前缀(YES)

  • 解题思路:直接暴力解,比较每一个成员前缀就行。

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 “”。

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        string ans="";
        //直接暴力解就行
        int i=0;

        while(i<strs[0].size())
        {
            char num=strs[0][i];
            
            for(int j=0;j<strs.size();j++)
            {
                if(i>=strs[j].size()||strs[j][i]!=num)
                {
                    return ans;
                }
            }

            ans+=num;
            i++;

        }

        return ans;
    }
};

题目88:合并两个有序数组(YES)

  • 解题思路:使用快速排序,切记快速排序只有找要交换的 i 和 j 才严格不等好,其他都要等号。

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

class Solution {
public:
    void quick_sort(vector<int>&nums1,int left,int right)
    {
        //递归结束条件
        if(left>=right)
        {
            return ;
        }

        int mid=nums1[(right+left)/2];
        int i=left;
        int j=right;

        while(i<=j)
        {
            while(nums1[i]<mid)
            {
                //这里要严格小于
                i++;
            }

            while(nums1[j]>mid)
            {
                j--;
            }

            if(i<=j)
            {
                swap(nums1[i],nums1[j]);
                i++;
                j--;
            }
        }

        //检查一下左右
        if(i<=right)
        {
            quick_sort(nums1,i,right);
        }

        if(left<=j)
        {
            quick_sort(nums1,left,j);
        }

    }

    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        //先将num2合并到num1中,最后使用快排进行一次排序就行
        for(int i=0;i<n;i++)
        {
            nums1[m]=nums2[i];
            m++;
        }
        int left=0;
        int right=nums1.size()-1;
        quick_sort(nums1,left,right);


    }
};

题目125:验证回文串(YES)

  • 解题思路:使用库函数std::tolower()。

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。

字母和数字都属于字母数字字符。

给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 。

class Solution {
public:
    bool isPalind(string ans)
    {
        int size=ans.size();
        int left=0;
        int right=size-1;

        while(left<=right)
        {
            if(ans[left]!=ans[right])
            {
                return false;
            }
            left++;
            right--;
        }

        return true;

    }

    bool isPalindrome(string s) {
        string ans;

        //遍历s将字母剥离出来
        for(int i=0;i<s.size();i++)
        {
            
            if((s[i]>='a'&&s[i]<='z')||(s[i]>='A'&&s[i]<='Z'))
            {
                ans+=std::tolower(s[i]);
            }else if(s[i]>='0'&&s[i]<='9')
            {
                ans+=std::tolower(s[i]);
            }
        }

        std::cout<<ans<<std::endl;

        return isPalind(ans);
    }
};

题目67:二进制求和(NO)

  • 解题思路: 模拟二进制求和

给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。

class Solution {
public:
    string addBinary(string a, string b) {  
        string ans;  
        reverse(a.begin(), a.end());  
        reverse(b.begin(), b.end());  

        int n = max(a.size(), b.size()), carry = 0;  

        for (int i = 0; i < n; ++i) 
        {  
            // 将当前位的值加到 carry 中  
            if (i < a.size()) 
            {   
                // 检查 a 是否还有位  
                carry += (a.at(i) == '1') ? 1 : 0;  
            }  
            if (i < b.size()) 
            { 
                // 检查 b 是否还有位  
                carry += (b.at(i) == '1') ? 1 : 0;  
            }  

            // 当前位的结果  
            ans.push_back((carry % 2) ? '1' : '0');  
        
            // 更新进位  
            carry /= 2; // 进位为 carry / 2  
        }  

        // 如果最后还有进位,添加 '1'  
        if (carry) 
        {  
            ans.push_back('1');  
        }  
    
        // 反转结果并返回  
        reverse(ans.begin(), ans.end());  
        return ans;  
    }     
};

题目144:二叉树的前序遍历(YES)

  • 解题思路:前序递归算法。

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    void preorder(TreeNode*root,vector<int>&ans)
    {
        if(root==nullptr)
        {
            return ;
        }

        ans.push_back(root->val);
        preorder(root->left,ans);
        preorder(root->right,ans);
    }


    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>ans;
        preorder(root,ans);

        return ans;
    }
};

题目235:二叉搜索树的最近公共祖先(NO)

  • 解题思路:先将每个节点二叉搜索树的搜索路径列出,对比这个搜索路径,找到最后一个相同的公共节点。

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */

class Solution {
public: 
    vector<TreeNode*>find_path(TreeNode*root,TreeNode*target)
    {
        //这里的搜索路径要包含自己
        vector<TreeNode*>path;
        TreeNode*temp=root;
        while(temp!=target)
        {
            path.push_back(temp);
            if(target->val<temp->val)
            {
                temp=temp->left;
            }else
            {
                temp=temp->right;
            }
        }
        path.push_back(target);

        return path;
    }


    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        vector<TreeNode*>path_p=find_path(root,p);
        vector<TreeNode*>path_q=find_path(root,q);

        //找到路径中最后一个相同的
        TreeNode*ans=NULL;
        int count=min(path_p.size(),path_q.size());
        for(int i=0;i<count;i++)
        {
            if(path_p[i]==path_q[i])
            {
                ans=path_p[i];
            }
        }

        return ans;
    }
};

面试题08.06:汉诺塔问题(NO)

  • 解题思路:递归思想,不要想。

在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。

请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。

你需要原地修改栈。

class Solution {
public:
    void hanota(vector<int>& A, vector<int>& B, vector<int>& C) 
    {
        int n = A.size();
        move(n, A, B, C);
    }

    void move(int n, vector<int>& A, vector<int>& B, vector<int>& C)
    {
        if (n == 1)
        {
            C.push_back(A.back());
            A.pop_back();
            return;
        }

        move(n-1, A, C, B);    // 将A上面n-1个通过C移到B
        C.push_back(A.back());  // 将A最后一个移到C
        A.pop_back();          // 这时,A空了
        move(n-1, B, A, C);     // 将B上面n-1个通过空的A移到C
    }
};

题目812:最大三角形面积(NO)

  • 解题思路:枚举。

给你一个由 X-Y 平面上的点组成的数组 points ,其中 points[i] = [xi, yi] 。从其中取任意三个不同的点组成三角形,返回能组成的最大三角形的面积。与真实值误差在 10-5 内的答案将会视为正确答案。

class Solution {
public:
    double triangleArea(int x1, int y1, int x2, int y2, int x3, int y3) {
        return 0.5 * abs(x1 * y2 + x2 * y3 + x3 * y1 - x1 * y3 - x2 * y1 - x3 * y2);
    }

    double largestTriangleArea(vector<vector<int>> & points) {
        int n = points.size();
        double ret = 0.0;
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                for (int k = j + 1; k < n; k++) {
                    ret = max(ret, triangleArea(points[i][0], points[i][1], points[j][0], points[j][1], points[k][0], points[k][1]));
                }
            }
        }
        return ret;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值