0%

刚接触Flutter开发时,不管是为了性能还是项目代码简洁等原因,总归还是会选择一个合适的状态管理工具。但是看着茫茫多的选择还是感觉无从下手,当然我也一样。下方记录一下各种状态管理(Riverpod、Provider、Getx)的使用,以便后续遇到其他项目使用不同状态管理时能快速上手。也希望为看到这篇文章的同学提供一些参考。

Riverpod

使用的前提需要注意,需要使用ProviderScope包裹父级节点。

Read more »

1.二叉树的前序遍历

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

示例 1:

img

1
2
输入:root = [1,null,2,3]
输出:[1,2,3]

示例 2:

1
2
输入:root = []
输出:[]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Definition for a binary tree node.
* public class TreeNode {
* public var val: Int
* public var left: TreeNode?
* public var right: TreeNode?
* public init() { self.val = 0; self.left = nil; self.right = nil; }
* public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; }
* public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) {
* self.val = val
* self.left = left
* self.right = right
* }
* }
*/
class Solution {
func preorderTraversal(_ root: TreeNode?) -> [Int] {
var result = [Int]()
guard let root = root else {
return result
}
result.append(root.val)
result += preorderTraversal(root.left)
result += preorderTraversal(root.right)
return result
}
}

解题思路:

  1. 前序遍历按照根节点->左子树->右子树的顺序访问
  2. 访问根节点
  3. 采用中序递归遍历左子树
  4. 采用中序递归遍历右子树
Read more »

1.字符串轮转

字符串轮转。给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成(比如,waterbottle是erbottlewat旋转后的字符串)。

示例1:

输入:s1 = “waterbottle”, s2 = “erbottlewat”
输出:True
示例2:

输入:s1 = “aa”, s2 = “aba”
输出:False
提示:

字符串长度在[0, 100000]范围内。
说明:

你能只调用一次检查子串的方法吗?

1
2
3
4
5
6
7
class Solution {
func isFlipedString(_ s1: String, _ s2: String) -> Bool {
if s1 == "" && s2 == "" { return true } //处理空字符串
guard s1.count == s2.count else {return false}
return (s1 + s1).contains(s2)
}
}

解题思路:

  1. 利用s1+s1拼接起来,这样子就包括所有的旋转字符串了
  2. 只要新的字符串包含s2直接返回true
Read more »

1.最小栈

设计一个支持 pushpoptop 操作,并能在常数时间内检索到最小元素的栈。

push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]


输出:
[null,null,null,null,-3,null,0,-2]

解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.

提示:

pop、top 和 getMin 操作总是在 非空栈 上调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class MinStack {

var head:ListNode?

init() {
head = ListNode(min:Int.max)
}

func push(_ val: Int) {
//每次push都记录最小值
head = ListNode(val: val, min: min(val, head!.min), next: head)
}

func pop() {
head = head?.next
}

func top() -> Int {
return head?.val ?? 0
}

func getMin() -> Int {
return head?.min ?? 0
}

class ListNode {
let val: Int
let min:Int
let next: ListNode?

init(val: Int = 0,min:Int = 0,next:ListNode? = nil) {
self.val = val
self.min = min
self.next = next
}

}

}


/**
* Your MinStack object will be instantiated and called as such:
* let obj = MinStack()
* obj.push(val)
* obj.pop()
* let ret_3: Int = obj.top()
* let ret_4: Int = obj.getMin()
*/

解题思路:

题目要求我们从栈元素中找到最小值,按照正常想,我们都会遍历一遍栈的元素,但是这样时间复杂度就是O(n),题目要求是O(1),一般遇到这种问题,就需要空间换时间了。
使用链表,在每个节点保存当前的最小值,每次push都记录当前元素对应的最小值,每个节点都一一对应一个最小值,这样子getMin时间复杂度就是O(1),同道理,这里用两个栈也可以做到一一对应也能解决。

Read more »

1.移除链表元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点

**示例 **

1
2
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class ListNode {
public var val: Int
public var next: ListNode?
public init() { self.val = 0; self.next = nil; }
public init(_ val: Int) { self.val = val; self.next = nil; }
public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; }
}
func removeElements(_ head: ListNode?, _ val: Int) -> ListNode? {
guard head != nil else { return head }
//虚拟头结点 也是新链表的头结点
let dummyHead = ListNode()
//新链表尾结点
var newTail = dummyHead

//用来遍历的链表头,swift传参都是不可变的
var curHead = head

//遍历链表
while curHead != nil {
if curHead?.val != val {
newTail.next = curHead
newTail = curHead!
}
curHead = curHead?.next
}
//尾部置空
newTail.next = nil

return dummyHead.next
}

解题思路:
这里用一个虚拟头结点来作为新链表的头结点会让代码更加的简洁,遍历传进来的链表,判断当前的链表是否是需要删除的如果不是需要删除的,让新链表尾结点下一个指向它,也就是尾部结点也是当前结点,最后把尾部结点置空,返回新节点头的下一个结点。

Read more »

1. 合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例 :

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func merge(_ nums1: inout [Int], _ m: Int, _ nums2: [Int], _ n: Int) {
//思路是使用双指针的思路,这里用到了归并排序的思想
var i1 = m - 1
var i2 = n - 1
var cur = nums1.count - 1
while i2 >= 0 { //这里必须要大于等于0 代表还没有合并结束
if i1 >= 0 && nums2[i2] < nums1[i1] {
nums1[cur] = nums1[i1]
i1 -= 1
}else{ // i1 < 0 || nums2[i2] >= nums1[i1] 这里i1已经为0了
nums1[cur] = nums2[i2]
i2 -= 1
}
cur -= 1
}
}

解题思路:

双指针法,从后面插入替换合并,把nums2数值添加到nums1,如果在前面插入会替换到后面的数字

只要nums2的指针索引>=0代表还没有合并结束,只要成功合并一次,两个指针索引都需要向后移动一位

这里还需要考虑到比如nums1的长度比nums2 数组长度短的情况,所以 else 里就是 // i1 < 0 || nums2[i2] >= nums1[i1] 这里i1已经为0了 这里直接把nums2的数字往nums1数组合并

这里解题思路用到了归并排序算法:

图片

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
  4. 重复步骤 3 直到某一指针达到序列尾;
  5. 将另一序列剩下的所有元素直接复制到合并序列尾。
Read more »

初识

作为一个移动端iOS开发,小程序也是有必要学习的,学好小程序的基本流程,会发现跟iOS原生开发很多都相似的,比如每个界面都有它的生命周期,数据绑定,响应事件等等,而且微信团队把它封装得非常易用,只要看文档,补充下CSS的知识就可以上手开发。

CSS布局知识

clssname .clssname

1
2
3
4
5
.clssname .clssname{
float:left;
height: 100rpx;
line-height: 100rpx;
}

代表 clssname 里的clssname样式更改

clssname view

1
2
3
4
.clssname view{
flex:1;
color:white;
}

代表 clssname 里所有的view样式更改

Read more »

二分查找算法(非递归):

  1. 二分查找算法有递归和非递归方式,下面我们讲解二分查找算法的非递归方式
  2. 二分查找法只适用于从有序的数列中进行查找(比如数字和字母等),将数列排序后再进行查找
  3. 二分查找法的运行时间为对数时间 O(㏒₂n) ,即查找到需要的目标位置最多只需要㏒₂n 步,假设从[0,99]的 队列(100 个数,即 n=100)中寻到目标数 30,则需要查找步数为㏒₂100 , 即最多需要查找 7 次( 2^6 < 100 < 2^7)

分治算法:

  1. 分治法是一种很重要的算法。字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或 相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题 的解的合并。这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变 换)……
  2. 分治算法可以求解的一些经典问题
  • 二分搜索
  • 大整数乘法
  • 棋盘覆盖
  • 合并排序
  • 快速排序
  • 线性时间选择
  • 最接近点对问题
  • 循环赛日程表
  • 汉诺塔
Read more »

1、使用SwiftRealm会导致没法预览报Updating took more than 5 seconds

花了点时间查找问题,最后发现是因为初始化数据库写在AppDelegate,写在SceneDelegate就没事了!

2、SwiftUI数据流温故知新 - 属性包装

@State

@State属性允许修改Struct的属性,这些属性在普通的Struct里面是不允许修改的。当把@State放置到属性前,该属性实际上会被放到Struct的外部存储起来,这意味着SwiftUI能够随时销毁和重建Struct而不会丢失属性的值。
@State包装的属性通常是设置成私有的,不让外部使用。如果想让外部使用,则应该使用@ObservedObject和@EnvironmentObject,他们能够使外部修改属性后,状态能够得到改变。
建议把@State包装的属性都设置成私有

@Published

@Published是SwiftUI最有用的包装之一,允许我们创建出能够被自动观察的对象属性,SwiftUI会自动监视这个属性,一旦发生了改变,会自动修改与该属性绑定的界面。
1.首先需要遵循ObservableObject属性

1
class Bag: ObservableObject { var items = [String]() }

2.包装属性

1
class Bag: ObservableObject { @Published var items = [String]() }

这样就完成了。@Published包装会自动添加willSet方法监视属性的改变。

@ObservedObject

@ObservedObject告诉SwiftUI,这个对象是可以被观察的,里面含有被@Published包装了的属性。
@ObservedObject包装的对象,必须遵循ObservableObject协议。也就是说必须是class对象,不能是struct。
@ObservedObject允许外部进行访问和修改。

@EnvironmentObject

@EnvironmentObject包装的属性是全局的,整个app都可以访问
需要注意的是,不需要给定默认值,由于该属性是整个app都可以访问的,SwiftUI会自动的从环境中取出来。
当有这样一个场景,A->B->C->D->E->F,A界面的数据要传递给F界面,假如使用@ObservedObject包装,则需要一层一层传递,而使用@EnvironmentObject则不需要,直接在F界面,通过SwiftUI环境直接取出来就行。
需要注意的是,当界面显示时,就会去环境中取,但是,假如之前没有把属性放到环境中,则程序会崩溃。

@Environment

@Environment与@EnvironmentObject作用是不同的,@Environment是从环境中取出预定义的值,比如获得当前是暗黑模式还是正常模式,屏幕的大小等等。

1
2
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Environment(\.managedObjectContext) var managedObjectContext

@Binding

@Binding也是非常重要的一个包装,声明一个属性是从外部获取的,并且与外部是共享的。相当于外部传过来的时候,不是传递的值。任何一方修改都会让SwiftUI的监视生效。

@GestureState

@GestureState能够让我们传递手势的状态,虽然使用@State也能实现,但@GestureState能让手势结束后我们回到最初的状态。

设置属性,设置zero意味着手势结束后,会回到最初的值。

1、使用pip3 安装Python3 的资源库

pip3 install xlwt
或者想要一次性安装多个库需要把需要安装的库放在requirements.txt,使用pip3安装的可以使用指令
pip3 install -r requirements.txt

2、python 合并拼接字符串

1
2
3
4
5
6
7
8
9
>>> a = ["hello", "world"]
>>> a
['hello', 'world']
>>> ' '.join(a)
'hello world'
>>> ','.join(a)
'hello,world'
>>> ''.join(a)
'helloworld'
Read more »