#力扣笔记

#416 分割等和子集
1、python解析式的写法,初始化列表真的很方便

dp = [[False] * (target + 1) for _ in range(n)]

2、自己写的dfs解法的事件复杂度应该为 ( n − 1 ) ! + ( n − 2 ) ! + . . . + 1 \left( n-1\right) !+\left( n-2\right) !+...+1 (n1)!+(n2)!+...+1
原来这特么的叫np问题啊。面对这种问题就待思考时间复杂度元素数目大小相关的动态规划算法了。

记录一下做这道题的一个体会:当i,j均匀增加的时候dp像一条线,而当特定的dp[i][j]为true时,像一个特殊的点,像一个里程碑。一个一个里程碑连接起来,就得到了组成target的所有元素。

另外如果从直观的角度去理解dp的话,可以这样理解:考虑当下的或者说是眼前的元素与==一个带有某种意义的集合(可能为前面的所有元素)==相融合的过程,把当前元素融入到这个意义集合里,就完成了状态的转移。把当前元素融入到意义集合的方法就是状态转移公式,集合所代表的这个意义,就是状态。这很像我自己对于递归的理解,子集的递归仿佛带有了某种意义。注意这种思维方式,可能对下次形成dp思路有帮助。

#322 零钱兑换

1、动态规划三要素:
(1)最优子结构
(2)状态转移方程
(3) 重叠子问题

动态规划问题的⼀般形式就是求最值。动态规划其实是运筹学的⼀种最优化 ⽅法,只不过在计算机问题上应⽤⽐较多,⽐如说让你求最⻓递增⼦序列 呀,最⼩编辑距离呀等等。 既然是要求最值,核⼼问题是什么呢?求解动态规划的核⼼问题是穷举。因 为要求最值,肯定要把所有可⾏的答案穷举出来,然后在其中找最值呗。 动态规划就这么简单,就是穷举就完事了?我看到的动态规划问题都很难 啊!⾸先,动态规划的穷举有点特别,因为这类问题存在「重叠⼦问题」,如果 暴⼒穷举的话效率会极其低下,所以需要「备忘录」或者「DP table」来优 化穷举过程,避免不必要的计算。 ⽽且,动态规划问题⼀定会具备「最优⼦结构」,才能通过⼦问题的最值得到原问题的最值。
动态规划解题套路框架 另外,虽然动态规划的核⼼思想就是穷举求最值,但是问题可以千变万化,穷举所有可⾏解其实并不是⼀件容易的事,只有列出正确的「状态转移⽅ 程」才能正确地穷举。 以上提到的重叠⼦问题、最优⼦结构、状态转移⽅程就是动态规划三要素。 具体什么意思等会会举例详解,但是在实际的算法问题中,写出状态转移⽅程是最困难的。

2、所谓最优子结构,就是子结构具有最优解,切子结构之间互相独立。

这个问题是动态规划问题,因为它具有「最优⼦结构」的。==要符合 「最优⼦结构」,⼦问题间必须互相独⽴。==啥叫相互独⽴?你肯定不想看数 学证明,我⽤⼀个直观的例⼦来讲解。 ⽐如说,你的原问题是考出最⾼的总成绩,那么你的⼦问题就是要把语⽂考 到最⾼,数学考到最⾼…… 为了每门课考到最⾼,你要把每门课相应的选 择题分数拿到最⾼,填空题分数拿到最⾼…… 当然,最终就是你每门课都 是满分,这就是最⾼的总成绩。 得到了正确的结果:最⾼的总成绩就是总分。因为这个过程符合最优⼦结 构,“每门科⽬考到最⾼”这些⼦问题是互相独⽴,互不⼲扰的。 但是,如果加⼀个条件:你的语⽂成绩和数学成绩会互相制约,此消彼⻓。 这样的话,显然你能考到的最⾼总成绩就达不到总分了,按刚才那个思路就 会得到错误的结果。因为⼦问题并不独⽴,语⽂数学成绩⽆法同时最优,所 以最优⼦结构被破坏。 回到凑零钱问题,为什么说它符合最优⼦结构呢?⽐如你想求 amount = 11 时的最少硬币数(原问题),如果你知道凑出 amount = 10 的最少硬币 数(⼦问题),你只需要把⼦问题的答案加⼀(再选⼀枚⾯值为 1 的硬币) 就是原问题的答案,因为硬币的数量是没有限制的,⼦问题之间没有相互 制,是互相独⽴的。

3、两种方法
自顶向下(递归,重点在于消除重叠子问题,使用记忆表dp)
自下向上(动态规划,从1开始填递归表,重点在于最优子结构、状态转移方程)

4、c语言和C++都包含INT_MAX

5、还是穷举,聪明的穷举。
自顶向下的穷举是线段式的、里程碑式的,一个点一个点连成串式的。
自底向上的穷举是连线式的,不断的自增1,最终达到最后的amount。已经脱离了题目本身,而是找到规则后,不断的去增长dp表。

#46 全排列

1、指针:
p是地址 (注意,该地址非p自身地址,而是指向对象的地址)
*p是数据内容

2、指向指针的指针:
int a;
int *p1;
int **p2;

*p1 = &a
*p2 = &p1

由此可以看出指针p是一种特殊的类型。如果要使用一个指针指向令一个指针,需要**两次
在这里插入图片描述
3、函数指针与函数指针数组
函数在内存中也有地址,是一片连续的内存区域
所以可以使用指针指向他
详细介绍看链接
c语言指针用法及实际应用详解,通俗易懂超详细! - 无际单片机的文章 - 知乎
https://zhuanlan.zhihu.com/p/388456835

4、关于力扣中int *returnSize和int **returnColumnSizes
https://blog.csdn.net/m0_52775920/article/details/121461911

5、malloc和new,都是开辟内存。
malloc需要自己制定内存大小,new会自动进行计算。malloc返回类型是void* (无指定类型指针)。需要强制转换。

6、int **ans = (int **)malloc(sizeof(int *) * 100000);
这句代码给我折磨到半死
其实就是先分配了100000个指针的空间。然后malloc返回了一个指针指向了第一个分配的空间。因为这个空间里装的是一个指针,所以只能用二阶指针指向这个空间(里边装的是一个指针)。
这样看的话,c语言是很严格的,虽然不知道内部是个什么原理(这个原理我不想深究了,有知道的大神麻烦告我一下)。但是格式之间需要严格的一一对应。而且,指针类型还是int,跨了两层也要指明一阶指针指向的空间里装的是一个int变量。

7、在定义指针的时候,一定记得,不仅要定义指针,还要告诉编译器,指针指向了哪里。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值