1002. Find Common Characters

该题目要在由字符串组成的数组中,找到所有字符串都存在的字符,包括重复的。下边给出两种解法

解法 1

这个也是首先想到的,但是效率不高

  1. 生成一个数组 arrayWithMap,这个数组中放字典
  2. 这个字典中,key 为字符,value 为这个字符在这个字符串中出现的次数
  3. 随机选取一个字符串(第一个),遍历这个字符串,取得的每一个字符去 arrayWithMap 中遍历,看每一个 map 是否存在该字符,如果存在,则对应map 的中 该字符 对应的 value - 1,当 value 为 0 时,移除,如果都存在,则该字符就是公共字符,放入数组中
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
func commonChars(A []string) []string {
resultArray := make([]string, 0)
arrayWithMap := make([]map[rune]int, len(A))

for idx, str := range A {
charMap := make(map[rune]int, 0)
for _, char := range str {
num, ok := charMap[char]
if ok {
charMap[char] = num + 1
} else {
charMap[char] = 1
}
}
arrayWithMap[idx] = charMap
}

for _, char := range A[0] {
exist := true
for _, charMap := range arrayWithMap {
num, ok := charMap[char]
if ok && num > 0 {
charMap[char] = num - 1
} else {
delete(charMap, char)
exist = false
break
}
}
if exist {
resultArray = append(resultArray, string(char))
}
}
return resultArray
}

解法 2

解法一提交上去发现,不管是时间还是空间,消耗都非常巨大,只打败了 46% 左右的人。后来看了第一名的解法,发现,真是个人才。

  1. 考虑到字母有 26 个,首先生成一个长度为 26 的数组 m,数组中存一个大数
  2. 遍历数组 A,把每一个字符串映射到一个数组temp 中,数组的索引代表 a - z,而对应的值,代表该字母在字符串中出现的次数。
  3. 然后把这个数组 tempm 逐位比较,取值小的哪一位,因为重复次数,总要以的为主,比如 look 中 o 存在 2 次,而 hour 中,o 存在 1 次,所以在结果中 o 最多出现 1 次。
  4. 当我们比较完之后,数组 m 中,值不为 0 的下标就是共同出现的字母,而对应的非 0 值,就是该字母出现的次数。
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
func min(a, b int) int {
if a < b {
return a
}
return b
}

func commonChars(A []string) []string {
m := make([]int, 26)

for i := 0; i < 26; i++ {
m[i] = (1 << 31) - 1
}

for _, str := range A {
tmp := make([]int, 26)
for _, c := range str {
tmp[byte(c)-'a']++
}
for c, num := range tmp {
m[c] = min(num, m[c])
}
}

out := make([]string, 0)
for idx, count := range m {
if count > 0 {
for i := count; i > 0; i-- {
out = append(out, string(byte(idx + 'a')))
}
}

}
return out
}

不得不说,是真的强 👍

随着组件化的发展,越来越多的东西被单独拆分出来,形成单独的库。在 iOS 中,我们通常用 Cocoapods 来进行管理包管理。本篇文章将解释如何制作自己的私有 pod 库,以及私有 pod 库的互相依赖。

本机环境:

macOS Mojave 10.14.5
Cocoapods 1.7.3
ruby 2.3.7p456 (2018-03-28 revision 63024) [universal.x86_64-darwin18]

制作私有库

制作私有库将分为以下几个步骤

👉1. 创建一个私有库

我们在 github 上创建一个仓库,叫做 Xiaoma,来存放我们的 pod 库代码,然后,打开终端,进入 桌面,执行以下命令

1
2
3
pod repo add Xiaoma https://github.com/xiao333ma/Xiaoma.git

pod lib create Xiaoma

pod 将会以交互式的方式询问一些配置项,根据需要进行选择。看起来是这个样子的

这样我们就创建了一个 Xcode 工程,pod 会自动帮我们打开。

👉2. 开发 pod 库

随着工程创建完毕,我们就可以进行愉快的开发了。在工程中,我们会看到有一个 pod 的子工程,里边有一个 Development Pods 文件夹,在这个文件夹下边,将会有我们所定义名称为 Xiaoma 的 pod 库文件夹。当我们新建一个文件的时候,应该保存在物理路径 ~/Desktop/Xiaoma/Xiaoma/Classes/

👉3. 修改 .podspec 文件

当我们开发完成之后,我们需要修改 podspec 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Pod::Spec.new do |s|
s.name = 'Xiaoma'
s.version = '0.1.0'
s.summary = '这是一个测试 pod 库'
s.description = "这是一个测试 pod 库,就是测试一下"
s.homepage = 'https://github.com/xiao333ma/Xiaoma'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'git' => 'xiao3333ma@gmail.com' }
s.source = { :git => 'https://github.com/xiao333ma/Xiaoma.git', :tag => s.version.to_s }
s.ios.deployment_target = '8.0'
s.source_files = 'Xiaoma/Classes/*.{h,m}'
s.public_header_files = 'Xiaoma/Classes/*.h'
s.dependency 'AFNetworking', '~> 2.3'
s.dependency 'Masonry'
end

命名挺清晰的,这里就不在赘述了。值得一提的是,当你依赖多个第三方库的时候,s.dependency 写多个就行了。可以参考 AFNetworking

👉4. 验证 pod 库

当我们开发完成 pod 库的时候,以及配置好对应的 podspec 文件后,就可以进行验证,看是否符合 pod 库的规则。如果我们只是作为 私有 pod 库 的时候,其实是可以不验证的,反正就是自己玩,验证与否,都可以。不想验证的同学,可以跳过这一步。

在终端中,在 ~/Desktop/Xiaoma 下,执行一下命令

1
pod lib lint Xiaoma.podspec

当返回结果是因为有警告而没有通过验证的时候,我们可以加上 --allow-warnings 来忽略警告

1
2
pod lib lint Xiaoma.podspec --allow-warnings

当获得类似如下提示时,pod 库,将通过验证。

👉5. 将代码推送到 github

接下来就是常规操作了,将代码推送到 github 上,打个 tag0.1.0

1
2
git tag '0.1.0'
git push --tags

👉6. 提交 pod 库

在终端执行以下命令,将 podspec 推送到远端。如果有警告,加上 --allow-warnings 来解决

1
pod repo push Xiaoma Xiaoma.podspec

👉7. 测试 pod 库

我们可以新建一个工程叫 PodTestpod init 之后,修改 Podfile 为以下

1
2
3
4
5
6
7
8
9
10
  
target 'PodTest' do
# Comment the next line if you don't want to use dynamic frameworks
# use_frameworks!

# Pods for PodTest

pod 'Xiaoma', :git => 'https://github.com/xiao333ma/Xiaoma.git', :tag => '0.1.0'

end

如果不出意外的话,我们就可以使用我们所制作的 pod 库了

👉8. 修改 pod 库

当我们写的代码出现 bug 或者需要添加功能的时候,我们就需要修改 pod 库。
开发完对应的功能的功能后,我们需要做以下几个步骤

  1. 修改 podspecs.version 加 1
  2. 验证或者不验证 podspce 的合法性
  3. push 到远端,并且打和 s.version 对应的 tag
  4. 提交 pod

这一波下来,黄花菜都凉了,下边介绍个懒方法

👉8.1 懒方法

当我们修改完代码后,直接 push 到 github 就行了,在 podfile 中,进行如下修改

1
2
3
4

#pod 'Xiaoma', :git => 'https://github.com/xiao333ma/Xiaoma.git', :tag => '0.1.0'

pod 'Xiaoma', :git => 'https://github.com/xiao333ma/Xiaoma.git', :branch => 'master'

这样的话,我们每次去拉取,都是 master 的代码,而不去管版本号,这样一步到位,方便省事。

接着我们在 PodTest 工程下执行 pod update,就会发现,我们已经同步到了最新的代码。

1
2
# 我们也可以指定对应的 git 提交记录,来回滚到之前的版本
pod 'Xiaoma', :git => 'https://github.com/xiao333ma/Xiaoma.git', :commit => '3f1c79b1ae3b66a2202dc663296c51ee587db4c6'

2. 私有 pod 库互相依赖

当我们有一个库需要依赖另外一个库的时候,就会有点麻烦了。当我们在 podspec 中写 s.dependency '***' 时,验证 pod 是会报错的,具体报错,大家可以试试。而私有库的依赖,我们需要建立自己的 spec 仓库。这里我会创建一个私有库叫做 XiaomaTools ,让 Xiaoma 去依赖它。

👉1 建立私有 spce 仓库

在 github 上建立一个仓库叫做 XiaomaPrivatePodSpecs,对应的地址为 https://github.com/xiao333ma/XiaomaPrivatePodSpecs.git

👉2 创建一个私有库

和上边的创建私有库不同,我们这次需要指定地址为 XiaomaPrivatePodSpecs 的地址

1
2
pod repo add XiaomaTools https://github.com/xiao333ma/XiaomaPrivatePodSpecs.git
pod lib create XiaomaTools

按照上述 1.2 开发 pod 库,1.3 修改 podspec 文件

👉3. 验证 pod 库

由于 XiaomaTools 会被别的库依赖,所以,它必须通过验证才可以,我们执行以下命令,来验证 podspec

1
pod lib lint XiaomaTools.podspec --allow-warnings

👉4. 将代码提交到 github 上

正常操作,并打上对应的 tag

👉5. 推送 podspec

在 XiaomaTools 下,执行一下命令,将 podspec 推送到 XiaomaPrivatePodSpecs.git 中,如果该 pod 库依赖了其他第三方库,需要加上 https://github.com/CocoaPods/Specs.git来向 pod 说明,我引用了第三方库,你需要去这个里边找到对应的库。

1
pod repo push XiaomaTools XiaomaTools.podspec --sources=https://github.com/xiao333ma/XiaomaPrivatePodSpecs.git,https://github.com/CocoaPods/Specs.git --allow-warnings

执行成功后,将会有如下提示,注意,这里是 - [Add] XiaomaTools (0.1.0)

👉6. 依赖 XiaomaTools

成功之后,我们就可以在 Xiaoma 中依赖 XiaomaTools

修改 Xiaoma.podspec 增加 s.dependency 'XiaomaTools'

修改 Xiaoma/Example 下边的 Podfile 增加下边两行

1
2
source 'https://github.com/xiao333ma/XiaomaPrivatePodSpecs.git'
source 'https://github.com/CocoaPods/Specs.git'

执行 pod update 将会安装 XiaomaTools

接下来让我们把 Xiaoma 更新到 0.2.0

修改 Xiaoma.podspec 中的 s.version0.2.0,把代码推送到远端,并打上 0.2.0tag,并在终端中,执行以下命令

1
pod lib lint Xiaoma.podspec --sources=https://github.com/xiao333ma/XiaomaPrivatePodSpecs.git,https://github.com/CocoaPods/Specs.git

由于 Xiaoma 依赖了 XiaomaTools,所以需要指定 sources 来告诉 pod 需要去 https://github.com/xiao333ma/XiaomaPrivatePodSpecs.git 中找XiaomaTools

提交到 github,并打 0.2.0tag

👉7. 验证

还记得我们的 PodTest 工程么,我们需要修改一下它的 podfile 文件

1
2
3
4
5
6
7
8
9
10
11
source 'https://github.com/xiao333ma/XiaomaPrivatePodSpecs.git'
source 'https://github.com/CocoaPods/Specs.git'
target 'PodTest' do
# Comment the next line if you don't want to use dynamic frameworks
# use_frameworks!

# Pods for PodTest

pod 'Xiaoma', :git => 'https://github.com/xiao333ma/Xiaoma.git', :tag => '0.2.0'

end

执行 pod update 将会发现,我们成功的安装了 XiaomaXiaomaTools

👉8. 修改 XiaomaTools

每次修改完代码,就要修改 spec 文件,更新版本号,并且 push 代码,打 tag,最后验证 spec 文件,并且 push podspec

3. 资源文件

当我们创建 pod 私有库的时候,pod 会帮我生成一个叫做 Assets 的文件夹,我们直接把图片放在这里边就可以了,比如我们创建一个 test.xcassets 我们可以再 Xiaoma.podspec 中这样写

1
2
3
s.resource_bundles = {
'XiaomaImage' => ['Xiaoma/Assets/test.xcassets']
}

这样,当我们执行 pod install 的时候,就会吧 test.xcassets 打成一个 bundle

当我们使用的时候,因为图片是在 bundle 中,所以有点小复杂,我们可以封装两个 category 来简化内部使用

首先获取我们 pod 库中文件所在的 bundleXiaomaView 为库中的一个文件)

1
2
3
4
5
6
7
8
9
10
@implementation NSBundle (Xiaoma)

+ (NSBundle *)XM_imageBundle {
NSString *bundlePath = [[NSBundle bundleForClass:[XiaomaView class]].resourcePath
stringByAppendingPathComponent:@"/XiaomaImage.bundle"];
return [NSBundle bundleWithPath:bundlePath];
}

@end

UIImage 添加一个 Category,使用 bundle 获取图片

1
2
3
4
5
6
7
@implementation UIImage (Xiaoma)

+ (UIImage *)XM_imageWithName:(NSString *)name {
return [UIImage imageNamed:name inBundle:[NSBundle XM_imageBundle] compatibleWithTraitCollection:nil];
}

@end

然后在我们使用的时候,就可以这样用啦

1
[UIImage XM_imageWithName:@"your-image-name"];

当我们需要增加或删除的时候,需要执行 pod install,否则,我们更改的内容,是不会同步到 bundle 中的

类似的,非图片资源也可以这样处理,如音频,视频等只需要这样写就可以和图片一样了

1
2
3
4
s.resource_bundles = {
'XiaomaImage' => ['Xiaoma/Assets/test.xcassets'],
'OtherResource' => ['Xiaoma/Assets/other/*']
}

在日常开发过程中,为了提升程序运行效率,以及用户体验,我们经常使用多线程。在使用多线程的过程中,难免会遇到资源竞争问题。我们采用锁的机制来确保线程安全。

线程安全

当一个线程访问数据的时候,其他的线程不能对其进行访问,直到该线程访问完毕。即,同一时刻,对同一个数据操作的线程只有一个。只有确保了这样,才能使数据不会被其他线程污染。而线程不安全,则是在同一时刻可以有多个线程对该数据进行访问,从而得不到预期的结果。

比如写文件和读文件,当一个线程在写文件的时候,理论上来说,如果这个时候另一个线程来直接读取的话,那么得到将是不可预期的结果。

为了线程安全,我们可以使用锁的机制来确保,同一时刻只有同一个线程来对同一个数据源进行访问。在开发过程中我们通常使用以下几种锁。

  1. NSLock
  2. NSRecursiveLock
  3. NSCondition
  4. NSConditionLock
  5. pthread_mutex
  6. pthread_rwlock
  7. POSIX Conditions
  8. OSSpinLock
  9. os_unfair_lock
  10. dispatch_semaphore
  11. @synchronized
Read more »
0%