C/C++每日一练(20230328)

简介: C/C++每日一练(20230328)

1. 环形链表


给定一个链表,判断链表中是否有环。


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


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


进阶:

你能用 O(1)(即,常量)内存解决此问题吗?


示例 1:

4a18acda10c1606aa5d1132b9de26d61.png



输入:head = [3,2,0,-4], pos = 1

输出:true

解释:链表中有一个环,其尾部连接到第二个节点。


示例 2:

1a6fcfc68d7340c39151075f7fa53150.png

输入:head = [1,2], pos = 0

输出:true

解释:链表中有一个环,其尾部连接到第一个节点。


示例 3:

3039274e08a9385ea77b20a81060ed40.png

输入:head = [1], pos = -1

输出:false

解释:链表中没有环。


提示:

   链表中节点的数目范围是 [0, 10^4]

   -10^5 <= Node.val <= 10^5

   pos 为 -1 或者链表中的一个 有效索引 。


出处:

https://edu.csdn.net/practice/23951838

代码1: 快慢指针



#include <bits/stdc++.h>
using namespace std;
struct ListNode
{
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};
class Solution
{
public:
    bool hasCycle(ListNode *head)
    {
        ListNode *faster = head;
        ListNode *slower = head;
        if (head == NULL)
            return false;
        while (faster != NULL && faster->next != NULL)
        {
            faster = faster->next->next;
            slower = slower->next;
            if (faster == slower)
                return true;
        }
        return false;
    }
};
ListNode* createRingNodeList(vector<int> nums, int pos = -1)
{
    if (nums.empty())
        return nullptr;
    ListNode *head = new ListNode(nums[0]);
    ListNode *tail = head;
    for (int i = 1; i < nums.size(); i++) {
        tail->next = new ListNode(nums[i]);
        tail = tail->next;
    }
    if (pos >= 0) {
        ListNode *p = head;
        while (pos--) {  // 找到尾指针指向的位置
            p = p->next;
        }
        tail->next = p;  // 构成环
    }
    return head;
}
int main()
{
    Solution s;
    vector<int> nums = {3,2,0,-4};
    /* 不用函数的创建: 
    ListNode *head = new ListNode(3);
    head->next = new ListNode(2);
    head->next->next = new ListNode(0);
    head->next->next->next = new ListNode(-4);
    head->next->next->next->next = head->next;
  */
  ListNode* head = createRingNodeList(nums, 1);
    cout << (s.hasCycle(head) ? "true" : "false") << endl;
    nums = {1,2};
  head = createRingNodeList(nums, 0);
    cout << (s.hasCycle(head) ? "true" : "false") << endl;
    nums = {1};
  head = createRingNodeList(nums, -1);
    cout << (s.hasCycle(head) ? "true" : "false") << endl;
    return 0;
}


输出:

true

true

false

代码2: 哈希表

#include <bits/stdc++.h>
using namespace std;
struct ListNode
{
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};
class Solution
{
public:
    bool hasCycle(ListNode *head)
    {
        unordered_set<ListNode*> s;
        while (head != nullptr) {
            if (s.count(head) != 0) {  
      // 如果当前节点已经在哈希表中,则说明形成了环
                return true;
            }
            s.insert(head);
            head = head->next;
        }
        return false;
    }
};
ListNode* createRingNodeList(vector<int> nums, int pos = -1)
{
    if (nums.empty())
        return nullptr;
    ListNode *head = new ListNode(nums[0]);
    ListNode *tail = head;
    for (int i = 1; i < nums.size(); i++) {
        tail->next = new ListNode(nums[i]);
        tail = tail->next;
    }
    if (pos >= 0) {
        ListNode *p = head;
        while (pos--) {  // 找到尾指针指向的位置
            p = p->next;
        }
        tail->next = p;  // 构成环
    }
    return head;
}
int main()
{
    Solution s;
    vector<int> nums = {3,2,0,-4};
  ListNode* head = createRingNodeList(nums, 1);
    cout << (s.hasCycle(head) ? "true" : "false") << endl;
    nums = {1,2};
  head = createRingNodeList(nums, 0);
    cout << (s.hasCycle(head) ? "true" : "false") << endl;
    nums = {1};
  head = createRingNodeList(nums, -1);
    cout << (s.hasCycle(head) ? "true" : "false") << endl;
    return 0;
}



2. 不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?



示例 1:

输入:m = 3, n = 7

输出:28


示例 2:


输入:m = 3, n = 2

输出:3

解释:从左上角开始,总共有 3 条路径可以到达右下角。

1. 向右 -> 向下 -> 向下

2. 向下 -> 向下 -> 向右

3. 向下 -> 向右 -> 向下


示例 3:

输入:m = 7, n = 3

输出:28


示例 4:

输入:m = 3, n = 3

输出:6


提示:

   1 <= m, n <= 100

   题目数据保证答案小于等于 2 * 10^9

出处:

https://edu.csdn.net/practice/23951839

原题代码:


#include <stdio.h>
#include <stdlib.h>
static int uniquePaths(int m, int n)
{
    int row, col;
    int *grids = (int*)malloc(m * n * sizeof(int));
    for (col = 0; col < m; col++)
    {
        grids[col] = 1;
    }
    for (row = 0; row < n; row++)
    {
        grids[row * m] = 1;
    }
    for (row = 1; row < n; row++)
    {
        for (col = 1; col < m; col++)
        {
            grids[row * m + col] = grids[row * m + col - 1] + grids[(row - 1) * m + col];
        }
    }
    return grids[m * n - 1];
}
int main()
{
    printf("%d\n", uniquePaths(3, 7));
    printf("%d\n", uniquePaths(3, 2));
    printf("%d\n", uniquePaths(7, 3));
    printf("%d\n", uniquePaths(3, 3));
    return 0;
}


输出:

28

3

28

6


C++代码:


方法一:动态规划

可以使用动态规划来求解,定义一个二维数组 dp,其中 dp[i][j] 表示从起点 (0,0) 到达位置 (i, j) 的不同路径数目。由于机器人只能向下或向右移动,因此到达位置 (i, j) 的路径数目只能从位置 (i-1, j) 或 (i, j-1) 转移而来,即: dp[i][j]=dp[i-1][j]+dp[i][j-1]


同时,对于第一行和第一列上的位置,由于它们只能由上方或左方转移而来,因此它们的 $dp$ 值均为 1。最终,到达右下角的路径数即为 dp[m-1][n-1]。

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> dp(m, vector<int>(n, 0));
        for (int i = 0; i < m; i++) {  // 处理第一列的情况
            dp[i][0] = 1;
        }
        for (int j = 0; j < n; j++) {  // 处理第一行的情况
            dp[0][j] = 1;
        }
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
};


方法二:组合

可以使用组合数学来求解,从起点 (0,0) 到达终点 (m-1,n-1),需要向下走m-1步,向右走n-1 步,因此总共需要走 m+n-2 步。在这 m+n-2 步中,向下走的步数有 m-1 步,向右走的步数有 n-1 步,因此总共不同的路径总数为:

class Solution {
public:
    int uniquePaths(int m, int n) {
        long long res = 1;
        for (int i = 1; i <= m-1; i++) {
            res = res * (n-1+i) / i;
        }
        return res;
    }
};



方法三:递归+记忆化搜索

可以使用递归+记忆化搜索的方法来求解,定义一个二维数组 memo,其中 memo[i][j] 表示从位置 $(i,j)$ 到达右下角的不同路径数目。递归函数 dfs(i,j) 表示从位置 (i,j) 到达右下角的不同路径数目,它可以从位置 (i+1,j) 或 (i,j+1) 转移而来,即:

对于边界情况,当 i=m-1 或 j=n-1 时,位置 (i,j) 已经到达右下角,此时路径数目为1。

eq.png

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> memo(m, vector<int>(n, -1));
        return dfs(0, 0, m, n, memo);
    }
    int dfs(int i, int j, int m, int n, vector<vector<int>>& memo) {
        if (i == m-1 || j == n-1) {
            return 1;
        }
        if (memo[i][j] != -1) {
            return memo[i][j];
        }
        int res = dfs(i+1, j, m, n, memo) + dfs(i, j+1, m, n, memo);
        memo[i][j] = res;
        return res;
    }
};




3. 字母表位置索引


描述:从键盘输入任意一个大写英文字母,要求它在26个字母表中的位置和其后面的第四个字母

例如:程序运行

输入:B<回车>。


输出:B在第2个位置,其后面第四个字母是F。

出处:

https://edu.csdn.net/practice/23951840

代码:

#include <stdio.h>
int main()
{
    char c, c2;
    printf("输入:");
    c = getchar();
    int m = 0, n = 0;
    if (c >= 'A' && c <= 'z')
    {
        m = c - 'A' + 1;
    if (m < 23)
    {
        c2 = c + 4;
        n = m + 4;
    }
    }
    if (n > 0)
        printf("%c在第%d个位置,其后面第四个字母是%c\n", c, m, c2);
    else
        printf("%c在第%d个位置,其后面没有第四个字母\n", c, m);
    return 0;
}



输入输出:

输入:B

B在第2个位置,其后面第四个字母是F

输入:V

V在第22个位置,其后面第四个字母是Z

输入:W

W在第23个位置,其后面没有第四个字母


目录
相关文章
|
7月前
|
Linux 监控 Ubuntu
Linux 终端操作命令(1)
Linux 终端操作命令(1)
98 1
Linux 终端操作命令(1)
|
7月前
|
算法 Java Go
Rust每日一练(Leetday0018) N皇后II、最大子数组和、螺旋矩阵
Rust每日一练(Leetday0018) N皇后II、最大子数组和、螺旋矩阵
48 1
Rust每日一练(Leetday0018) N皇后II、最大子数组和、螺旋矩阵
|
7月前
|
Linux 监控 Shell
Linux 终端命令之文件浏览(4) head, tail
Linux 终端命令之文件浏览(4) head, tail
61 0
Linux 终端命令之文件浏览(4) head, tail
|
7月前
|
Shell Linux 机器学习/深度学习
Linux 终端操作命令(3)内部命令用法
Linux 终端操作命令(3)内部命令用法
92 0
Linux 终端操作命令(3)内部命令用法
|
7月前
|
Python Linux Ubuntu
Linux系统部署Python语言开发运行环境
Linux系统部署Python语言开发运行环境
220 0
Linux系统部署Python语言开发运行环境
|
7月前
|
Go Unix 开发者
Go语言time库,时间和日期相关的操作方法
Go语言time库,时间和日期相关的操作方法
102 0
Go语言time库,时间和日期相关的操作方法
|
7月前
|
C++ 存储 Serverless
力扣C++|一题多解之数学题专场(2)
力扣C++|一题多解之数学题专场(2)
50 0
力扣C++|一题多解之数学题专场(2)
|
7月前
|
Go 机器学习/深度学习 Rust
Golang每日一练(leetDay0119) 反转字符串I\II Reverse String
Golang每日一练(leetDay0119) 反转字符串I\II Reverse String
88 0
Golang每日一练(leetDay0119) 反转字符串I\II Reverse String
|
7月前
|
Java Go C++
Golang每日一练(leetDay0115) 重新安排行程、递增的三元子序列
Golang每日一练(leetDay0115) 重新安排行程、递增的三元子序列
64 0
Golang每日一练(leetDay0115) 重新安排行程、递增的三元子序列
|
7月前
|
Java Go C++
Golang每日一练(leetDay0111) 摆动排序II\I Wiggle Sort
Golang每日一练(leetDay0111) 摆动排序II\I Wiggle Sort
57 0
Golang每日一练(leetDay0111) 摆动排序II\I Wiggle Sort