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;
}
遇到的问题:
在实现链表的衔接时,出现访问错误内存的问题。我不够清晰的点有:
-
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) {} * }; */ -
区分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];
}
遇到的问题:
-
未确定的变量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! -
看到大神写的代码,优化了内存(跪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;
}
遇到的问题:
- 不清楚如何讨论子序列,每一个位置似乎都有无尽可能。所以可以选择记录每一个位置上拥有的最大上升子序列和
- 未建立起递推公式,没找到合理的规律。按照双层循环的逻辑(i遍历整个数组,j遍历区间[0, i)的数组),只需要比较nums[i]与nums[j],但凡nums[i]>nums[j],就把dp[i]换成更大的统计长度
- 严格上升这个条件:是每一位nums[i]>nums[i-1],1->2->2->3不算做严格上升
- 虽然cpp里有
vector<int> one{};这种用大括号初始化的写法,但使用vector<int> one{n, 1};试图创建n个元素并初始化为1的语句则不行,无法成功开辟空间