leetcode题库1-10

1. 树的最小深度

求给定二叉树的最小深度。最小深度是指树的根结点到最近叶子结点的最短路径上结点的数量。

代码:

#include<math.h>
class Solution {
public:
    int run(TreeNode *root) {
        if(root == nullptr)
            return 0;
        if(root->left == nullptr && root->right == nullptr)
            return 1;
        if(root->left == nullptr || root->right == nullptr)
            return 1 + max(run(root->left), run(root->right));
        return 1 + min(run(root->left), run(root->right));
    }
};

2. 后缀表达式求值

计算逆波兰式(后缀表达式)的值
运算符仅包含"+","-","“和”/",被操作数可能是整数或其他表达式
例如:
[“2”, “1”, “+”, “3”, "
"] -> ((2 + 1) * 3) -> 9
[“4”, “13”, “5”, “/”, “+”] -> (4 + (13 / 5)) -> 6

思想:
遇到非操作符的字符串均入栈,碰到操作符则出栈并进行运算
代码:

#include<stack> //stack头文件
#include<stdlib.h> //stoi函数(字符串转换成十进制数)的头文件
using namespace std;
class Solution {
public:
    int evalRPN(vector<string> &tokens) {
        stack<int> numbers;
        int result;
        int length = tokens.size();
        for(int i = 0; i < length; i++)
        {
           if(tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/")
           {
               int right = numbers.top();//注意出栈顺序分别是表达式右左数值
               numbers.pop();
               int left = numbers.top();
               numbers.pop();
               if(tokens[i] == "+")
                   result = left + right;
               else if(tokens[i] == "-")
                   result = left - right;
               else if(tokens[i] == "*")
                   result = left * right;
               else
               {
                   if(right == 0)
                       return 0;
                   result = left / right;
               } 
               numbers.push(result);//每次运算表达式结果还需入栈
           }
            else
                numbers.push(stoi(tokens[i]));//将字符串转换成数值后并入栈
        }
        return numbers.top();
    }
};

3. max-point- on -line

对于给定的n个位于同一二维平面上的点,求最多能有多少个点位于同一直线上.

思路:循环遍历每个点,先统计其他点与当前点的重合个数dup以及与当前点在同一条垂直线上vlt的个数(斜率不存在的情况),再统计其他点与当前点在同一条直线的个数(斜率存在的情况),可利用Map统计这个点相对于其他点的不同斜率的个数,最后比较得到最多的在同一条直线上的点个数。

代码:

/**
 * Definition for a point.
 * struct Point {
 *     int x;
 *     int y;
 *     Point() : x(0), y(0) 
 *     Point(int a, int b) : x(a), y(b) {}
 * };
 */
#include<map> //map的头文件
#include<cmath>//max函数的头文件
class Solution {
public:
    int maxPoints(vector<Point> &points) {
        int length = points.size();
        if(length < 2)
            return length;
        int max_points = 0; 
        for(int i = 0; i < length; i++)
        {
            int dup = 0, vlt = 0, curmax = 0;
            Point a = points[i];
            map<float, int> pmap;
            for(int j = 0; j < length; j ++)
            {
                if( i == j) continue;
                else{
                     Point b = points[j];
                     if(a.x == b.x)
                     {
                        if(a.y == b.y)
                           dup ++;
                        else
                           vlt ++;
                     }
                     else
                     {
                        float key = (float)(a.y - b.y)/(a.x-b.x);
                        if(pmap[key] == 0)
                            pmap[key] = 2;//注意点1
                        else
                             pmap[key] += 1;
                        curmax = max(curmax, pmap[key]);
                     }
                }
            }
            curmax = max(curmax, vlt + 1);//注意点2
            max_points = max(max_points, curmax + dup);//注意点3
        }
        return max_points;//注意max_points是整个函数的全局变量,而curmax是for循环中的局部变量
    }
};

4. sort-list

在O(n log n)的时间内使用常数级空间复杂度对链表进行排序。

思路:
因为题目要求复杂度为O(nlogn),故可以考虑归并排序的思想。
归并排序的一般步骤为:
1)将待排序数组(链表)取中点并一分为二;
2)递归地对左半部分进行归并排序;
3)递归地对右半部分进行归并排序;
4)将两个半部分进行合并(merge),得到结果。

所以对应此题目,可以划分为三个小问题:
1)找到链表中点 (快慢指针思路,快指针一次走两步,慢指针一次走一步,快指针在链表末尾时,慢指针恰好在链表中点);
2)写出merge函数,即如何合并链表。 (见merge-two-sorted-lists 一题解析)
3)写出mergesort函数,实现上述步骤。

代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *sortList(ListNode *head) {
        if(head == nullptr || head->next == nullptr)//链表为空或者只有一个结点
            return head;
        ListNode *slow = head, *fast = head->next;
        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
        }
        ListNode *right = sortList(slow->next);
        slow->next = nullptr;
        ListNode *left = sortList(head);
        return mergeList(left, right);
    }
    ListNode *mergeList(ListNode *L1, ListNode *L2)
    {
        if(L1 == nullptr)
            return L2;
        if(L2 == nullptr)
            return L1;
        ListNode dummy(0);//注意这里不是指针,所以*p赋值时需要有地址符号
        ListNode *p = &dummy;
        while(L1 && L2)
        {
            if(L1->val < L2->val)
            {
                p->next = L1;
                L1 = L1->next;
            }
            else
            {
                p->next = L2;
                L2 = L2->next;
            }
            p = p->next;
        }
        if(L1 == nullptr)
            p->next = L2;
        if(L2 ==  nullptr)
            p->next = L1;
        return dummy.next;//注意这里不是dummy->next
    }
};

5. 使用插入排序对链表进行排序。

代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
   ListNode * insertionSortList(ListNode * head) {
        ListNode dummy(0);//注意点1,这里不是指针
        ListNode * cur = head;
        ListNode * pre;
        while(cur){
            //记录链表的下一个结点,用于cur后移
            ListNode * next = cur->next;
            pre = &dummy;
            //跳过小于cur->val的结点
            while(pre->next && pre->next->val < cur->val)
                pre = pre->next;
            //将cur插入pre->next 前
            cur->next = pre->next;
            pre->next = cur;
            cur = next;
        }
        return dummy.next;//注意点2,不能写成dummy->next
    }
};

6. 二叉树的后序遍历

求给定的二叉树的后序遍历。
例如:
给定的二叉树为{1,#,2,3},返回[3,2,1].

思路:后序遍历是左右根,根据栈先进后出的原则,即进栈时是根左右,只要保证顺序根右左的方式来保存元素,再将其reverse后即变成左右根了。
代码:

 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> postorderTraversal(TreeNode *root) {
        vector<int> res;
        if(root == nullptr)
            return res;
        stack<TreeNode*> stk;
        stk.push(root);
        while(stk.size())
        {
            TreeNode *p = stk.top();
            stk.pop();
            res.push_back(p->val);
            if(p->left != nullptr)
                stk.push(p->left);
            if(p->right != nullptr)
                stk.push(p->right);
         }
        reverse(res.begin(), res.end());
        return res;
    }
};

7. 二叉树的前序遍历

求给定的二叉树的前序遍历。
例如:
给定的二叉树为{1,#,2,3},返回:[1,2,3].

思路:和后序遍历一样,注意进栈顺序和后序遍历的进栈顺序不一样即为根右左进栈,出栈即为根左右(前序遍历)了。

代码:

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> res;
        if(root == nullptr)
            return res;
        stack<TreeNode*> stk;
        stk.push(root);
        while(stk.size())
        {
            TreeNode *p = stk.top();
            res.push_back(p->val);
            stk.pop();
            if(p->right != nullptr)
                stk.push(p->right);
            if(p->left != nullptr)
                stk.push(p->left);
        }
        return res;
    }
};

8. reorder -list

将给定的单链表L: L 0→L 1→…→L n-1→L n,
重新排序为: L 0→L n →L 1→L n-1→L 2→L n-2→…
要求使用原地算法,并且不改变节点的值
例如:
对于给定的单链表{1,2,3,4},将其重新排序为{1,4,2,3}.

思路:

  1. 使用快慢指针来找到链表的中点,并将链表从中点处断开,形成两个独立的链表。
  2. 将第二个链翻转。
  3. 将第二个链表的元素间隔地插入第一个链表中。
    上面的第二步是将后半段链表翻转,那么我们其实可以借助栈的后进先出的特性来做,如果我们按顺序将所有的结点压入栈,那么出栈的时候就可以倒序了,实际上就相当于翻转了链表。控制出栈结点的个数,然后我们要做的就是将每次出栈的结点隔一个插入到正确的位置,从而满足题目中要求的顺序。比如对于 1->2->3->4,栈顶只需出一个结点4,然后加入原链表之后为 1->4->2->3->(4),因为在原链表中结点3之后是连着结点4的,虽然我们将结点4取出插入到结点1和2之间,但是结点3后面的指针还是连着结点4的,所以我们要断开这个连接,这样才不会出现环,由于此时结点3在栈顶,所以我们直接断开栈顶结点即可。

代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    void reorderList(ListNode *head) {
        if (head == nullptr || head->next == nullptr || head->next->next == nullptr) 
            return;
        stack<ListNode*> stk;
        ListNode *cur = head;
        while (cur) {
            stk.push(cur);
            cur = cur->next;
        }
        int count = ((int)stk.size() - 1) / 2;
        cur = head;
        while (count > 0) {
            auto insert = stk.top(); 
            stk.pop();
            ListNode *next = cur->next;
            cur->next = insert;
            insert->next = next;
            cur = next;
            count --;
        }
        stk.top()->next = nullptr;
    }
};

9. 求环入口结点

对于一个给定的链表,返回环的入口节点,如果没有环,返回null
拓展:你能给出不利用额外空间的解法么?

思路:
在这里插入图片描述
a=c;
所以当快慢指针第一次相遇后,保持一个指针不动,另一个指针从X(头)开始移动,两个相遇的结点即为环入口结点。
证明a=c:
假设快慢指针走了n步之后相遇在Z点,那么快指针的路程是
2n=a+b+c+b…(1)
慢指针的路程是
n=a+b,即2n=a+b+a+b…(2)
两式相减即可得到a=c;

代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(head == nullptr)
            return nullptr;
        ListNode *slow = head, *fast = head;//快指针和慢指针一开始都是从head出发;
        while(fast && fast->next)
        {
            slow = slow->next;//慢指针每次走一步
            fast = fast->next->next;//快指针每次走两步
            if(fast == slow)//快慢指针第一次相遇
                break;
        }
        if(!fast || !fast->next)
            return nullptr;
        slow = head;//快慢指针第一次相遇后,快指针从相遇处每次移动一步,慢指针从head开始每次移动一步。
        while(slow != fast)
        {
            slow = slow->next;
            fast = fast->next;
        }
        return slow;
    }
};

10. 判断链表是否有环

判断给定的链表中是否有环
扩展:
你能给出不利用额外空间的解法么?

代码:

/**
 * 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) {
        if(head == nullptr || head->next == nullptr)
            return false;
        ListNode *slow = head, *fast = head;
        while(fast && fast->next)
        {
            fast = fast->next->next;
            slow = slow->next;
            if(slow == fast)
                return true;
        }
        return false;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Leetcode题库是一个包含了各种算法和数据结构问题的在线题库,供程序员练习和提升技能使用。这个题库中涵盖了大量的题目,包括但不限于图遍历、最短路径、有效的括号、字符串解码、Z字形变换、最长公共前缀、字符串相乘、颠倒字符串中的单词、比较版本号、反转字符串、压缩字符串、验证IP地址等等。它提供了java实现的leetcode解法,这些解法的代码规范,可读性良好,并且其中的解法思想并不受语言限制。通过解决这些题目,程序员可以提高自己的算法和编码能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [leetcode题库-leetcode-java:LeetcodeJava代码](https://download.csdn.net/download/weixin_38661100/19901136)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [LeetCode算法题整理(200题左右)](https://blog.csdn.net/qq_38253797/article/details/126827454)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值