day3

57 阅读3分钟

day3

合并两个有序链表

  • 当两个链表中的节点都存在时,比较节点数值的大小,较小的一方接到p中,并往后顺一位;当遍历完其中任一链表后,把另一个链表剩下的接到p->next上
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        ListNode* head; // 这里说明head是个指针,未分配结构体的存储空间
        ListNode* p = new ListNode(); // p分配了实体,并执行遍历
        head = p;
        while(list1 && list2){
            if(list1->val <= list2->val){
                p->next = list1;
                p = list1;
                list1 = list1->next;
            }else{
                p->next = list2;
                p = list2;
                list2 = list2->next;
            }
        }
        if(list1) p->next = list1;
        if(list2) p->next = list2;
        return head->next;
    }

遇到的问题:

在实现链表的衔接时,出现访问错误内存的问题。我不够清晰的点有:

  1. cpp中创建结构体对象的各种方法。使用ListNode* head;无法申请内存,此处不能类比创建STL容器的写法。应该采用申请一个具有结构体的对象(会创建具有结构体大小的内存空间),再使用一个指针指向该对象,从而通过指针来访问对象

    /**
     * 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) {}
     * };
     */
    
  2. 区分c和c++遍历链表的节点访问问题。p仅申请了一处内存(size=sizeof(ListNode)),cpp可以使用

    p->next = list1;
    p = p->next;
    

    对于c而言,则应通过解答代码中的写法完成(存疑)

不同路径

  • 高中学的,用组合求解(略;没学会)
  • 动态规划,每个格子都是上面的格子和左边的格子情况之和,换成递推公式也就是dp[m][n] = dp[m-1][n] + dp[m][n-1],而最左的一列和最上的一行,都是只有唯一的路径能到达,所以全部初始化为1
    int uniquePaths(int m, int n) {
        // 一共有m+n-1的长度要走,每个格子除了最右和最下只有一条路
        long long dp[m][n];
        // dp[m][n] = dp[m-1][n] + dp[m][n-1];
        // 初始化dp[0]={1}、dp[0][i]={1}
        dp[0][0] = 1;
        int x=m;
        while(--x){
            dp[x][0] = 1;
        }
        int y=n;
        while(--y){
            dp[0][y] = 1;
        }
        for(int x=0; x<m-1; ++x){
            for(y=0; y<n-1; ++y){
                dp[x+1][y+1] = dp[x][y+1] + dp[x+1][y];
            }
        }
        return dp[m-1][n-1];
    }

遇到的问题:

  1. 未确定的变量n(需要通过键盘输入)可以定义一个数组,比如

    int m, n;
    std::cin >> m >> n;
    int nums[m][n];
    

    但是不能用未确定的变量对数组初始化!

    int nums[m][n](0); // no!no!no!
    

    就算把初始化展开写也不行,因为该数组依然是由编译期不能确定的变量定义来的

    int nums[m][n];
    nums[0] = {0}; // no!no!no!
    
  2. 看到大神写的代码,优化了内存(跪TAT)

    class Solution {
    public:
        int uniquePaths(int m, int n) {
            vector<int> dp(n,1);
            for(int i = 1;i < m;i++)
            {
                for(int j = 1;j < n;j++)
                {
                    dp[j] += dp[j-1];
                }
            }
            return dp[n-1];
        }
    };
    

最长递增子序列

  • 动态规划:设定数组,记录到当前位置的所有子序列
int lengthOfLIS(vector<int>& nums) {
    int len = nums.size(), ans=0;
    if(len<2) return len;
    vector<int> dp(len, 1);
    for(int i=0; i<len; ++i){
        for(int j=0; j<i; ++j){
            if(nums[i] > nums[j]) dp[i] = max(dp[i], dp[j]+1);
        }
        if(dp[i] > ans) ans = dp[i];
    }
    return ans;
}

遇到的问题:

  1. 不清楚如何讨论子序列,每一个位置似乎都有无尽可能。所以可以选择记录每一个位置上拥有的最大上升子序列和
  2. 未建立起递推公式,没找到合理的规律。按照双层循环的逻辑(i遍历整个数组,j遍历区间[0, i)的数组),只需要比较nums[i]与nums[j],但凡nums[i]>nums[j],就把dp[i]换成更大的统计长度
  3. 严格上升这个条件:是每一位nums[i]>nums[i-1],1->2->2->3不算做严格上升
  4. 虽然cpp里有vector<int> one{};这种用大括号初始化的写法,但使用vector<int> one{n, 1};试图创建n个元素并初始化为1的语句则不行,无法成功开辟空间