Merge branch 'youngyangyang04:master' into master

This commit is contained in:
ironartisan
2021-08-19 14:42:13 +08:00
committed by GitHub
6 changed files with 253 additions and 6 deletions

View File

@ -304,8 +304,7 @@ var removeElements = function(head, val) {
};
```
Swift:
Swift
```swift
/**
* Definition for singly-linked list.

View File

@ -334,6 +334,43 @@ fun reverseList(head: ListNode?): ListNode? {
}
```
Swift
```swift
/// 双指针法 (迭代)
/// - Parameter head: 头结点
/// - Returns: 翻转后的链表头结点
func reverseList(_ head: ListNode?) -> ListNode? {
if head == nil || head?.next == nil {
return head
}
var pre: ListNode? = nil
var cur: ListNode? = head
var temp: ListNode? = nil
while cur != nil {
temp = cur?.next
cur?.next = pre
pre = cur
cur = temp
}
return pre
}
/// 递归
/// - Parameter head: 头结点
/// - Returns: 翻转后的链表头结点
func reverseList2(_ head: ListNode?) -> ListNode? {
return reverse(pre: nil, cur: head)
}
func reverse(pre: ListNode?, cur: ListNode?) -> ListNode? {
if cur == nil {
return pre
}
let temp: ListNode? = cur?.next
cur?.next = pre
return reverse(pre: cur, cur: temp)
}
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)

View File

@ -33,7 +33,7 @@
* 1 <= nums.length <= 2500
* -10^4 <= nums[i] <= 104
## 方法一 动态规划
## 思路
最长上升子序列是动规的经典题目这里dp[i]是可以根据dp[j] j < i推导出来的那么依然用动规五部曲来分析详细一波
@ -190,10 +190,130 @@ const lengthOfLIS = (nums) => {
};
```
*复杂度分析*
- 时间复杂度O(nlogn)。数组 nums 的长度为 n我们依次用数组中的元素去更新 dp 数组,相当于插入最后递增的元素,而更新 dp 数组时需要进行 O(logn) 的二分搜索,所以总时间复杂度为 O(nlogn)。
- 时间复杂度O(n^2)。数组 nums 的长度为 n我们依次用数组中的元素去遍历 dp 数组,而遍历 dp 数组时需要进行 O(n) 次搜索,所以总时间复杂度为 O(n^2)。
- 空间复杂度O(n),需要额外使用长度为 n 的 dp 数组。
## 方法二 贪心策略+二分搜索
使用贪心策略和二分搜索可以进一步将算法时间复杂度将为O(nlogn)。
## 思路
为了使得到的子序列尽可能长,我们需要使序列上升得尽可能慢。
对于长度为n的数组 nums我们从0到n-1依次遍历数组中的每个元素nums[i],更新在0到i范围内最长上升子序列的长度len以及 在0到i范围内上升子序列的长度为1到len时对应长度子序列最右端的最小值将结果保存在list中。实际编码过程中list长度即为len。
## 可行性
当我们遍历完数组nums中第n-1个元素时list中保存的是0到n-1范围内最长上升子序列的长度即为所求。
## 算法复杂度分析
1. list中的元素是单调递增的。可以用反证法来证明假设对于0<=i<j<len有list[i]>=list[j]那么我们可以在list[j]对应的子序列中删除最后j-i个元素得到长度与list[i]相同的子序列其最右端的值max<list[j]<=list[i],与list的定义矛盾
2. 假设我们已经得到0到i-1范围内对应的list,我们可以在O(logn)的时间复杂度内更新list,得到0到i范围内的list
1. if(nums[i]>list[len-1],此时list中子序列长度为1到len的对应的最右端最小值不变并新增长度为len+1的子序列最右端的最小值为nums[i],时间复杂度O(1);
2. if(nums[i]<=list[len-1])此时我们可以在0到len-1范围内找到k,list[k]为>=nums[i]的最小值,由于list单调递增所以我们可以使用二分搜索在O(logn)的时间复杂度内找到k。
1. 对于0<=j<k,list[j]<nums[i]恒成立对应list[j]的值不需要更新
2. 对于list[k]其值更新为nums[i],因为原本list[k]对应的子序列的倒数第二项的值可以=list[k-1]<nums[i]。
3. 对于k<j<=len-1,对应的list[j]不需要更新因为这些list[j]对应的子序列的倒数第二项的值>nums[i];
3. 综上算法时间复杂度为O(nlogn),空间复杂度为O(n),需要O(n)的空间保存list。
代码如下
Java
```java
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
if(n==0){return 0;}
List<Integer> list=new ArrayList<>();
list.add(nums[0]);
for (int i = 1; i < n; ++i) {
if (nums[i] > list.get(list.size()-1)) {
list.add(nums[i]);
} else {
int k=binarySearch(list,nums[i]);
list.set(k,nums[i]);
}
}
return list.size();
}
int binarySearch(List<Integer>list, int num){
int len=list.size();
int l=0,r=len-1,ans=len-1;
while(l<=r){
int mid=l+(r-l)/2;
if(list.get(mid)<num){
l=mid+1;
}else{
r=mid-1;
ans=mid;
}
}
return ans;
}
}
```
实际运行过程中list的长度不会超过n所以我们可以用数组来模拟list代码如下。
Java
```java
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
if(n==0){return 0;}
//初始化listlen记录list长度
int[] list=new int[n];
int len=0;
//添加元素到list并更新len的值
list[len++]=nums[0];
for (int i = 1; i < n; ++i) {
if (nums[i] > list[len-1]) {
list[len++]=nums[i];
} else {
int k=binarySearch(list,len,nums[i]);
list[k]=nums[i];
}
}
return len;
}
int binarySearch(int[] list,int len, int num){
int l=0,r=len-1,ans=len-1;
while(l<=r){
int mid=l+(r-l)/2;
if(list[mid]<num){
l=mid+1;
}else{
r=mid-1;
ans=mid;
}
}
return ans;
}
}
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)

View File

@ -227,7 +227,34 @@ class Solution:
return dp[n]
```
Go
```golang
func integerBreak(n int) int {
/**
动态五部曲
1.确定dp下标及其含义
2.确定递推公式
3.确定dp初始化
4.确定遍历顺序
5.打印dp
**/
dp:=make([]int,n+1)
dp[1]=1
dp[2]=1
for i:=3;i<n+1;i++{
for j:=1;j<i-1;j++{
// i可以差分为i-j和j。由于需要最大值故需要通过j遍历所有存在的值取其中最大的值作为当前i的最大值在求最大值的时候一个是j与i-j相乘一个是j与dp[i-j].
dp[i]=max(dp[i],max(j*(i-j),j*dp[i-j]))
}
}
return dp[n]
}
func max(a,b int) int{
if a>b{
return a
}
return b
}
```
Javascript:
```Javascript

View File

@ -948,6 +948,70 @@ class MyLinkedList {
}
```
Swift
```Swift
class MyLinkedList {
var size = 0
let head: ListNode
/** Initialize your data structure here. */
init() {
head = ListNode(-1)
}
/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
func get(_ index: Int) -> Int {
if size > 0 && index < size {
var tempHead = head
for _ in 0..<index {
tempHead = tempHead.next!
}
let currentNode = tempHead.next!
return currentNode.val
} else {
return -1
}
}
/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
func addAtHead(_ val: Int) {
addAtIndex(0, val)
}
/** Append a node of value val to the last element of the linked list. */
func addAtTail(_ val: Int) {
addAtIndex(size, val)
}
/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
func addAtIndex(_ index: Int, _ val: Int) {
if index > size {
return
}
let idx = (index >= 0 ? index : 0)
var tempHead = head
for _ in 0 ..< idx {
tempHead = tempHead.next!
}
let currentNode = tempHead.next
let newNode = ListNode(val, currentNode)
tempHead.next = newNode
size += 1
}
/** Delete the index-th node in the linked list, if the index is valid. */
func deleteAtIndex(_ index: Int) {
if size > 0 && index < size {
var tempHead = head
for _ in 0 ..< index {
tempHead = tempHead.next!
}
tempHead.next = tempHead.next!.next
size -= 1
}
}
}
```
-----------------------

View File

@ -103,7 +103,7 @@ dp[0][j]i为0存放编号0的物品的时候各个容量的背包
那么很明显当 j < weight[0]的时候dp[0][j] 应该是 0因为背包容量比编号0的物品重量还小
当j >= weight[0]dp[0][j] 应该是value[0]因为背包容量放足够放编号0物品。
当j >= weight[0]dp[0][j] 应该是value[0]因为背包容量放足够放编号0物品。
代码初始化如下:
```