3-sum

题目

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
[15] 3Sum  

https://leetcode.com/problems/3sum/description/

* algorithms
* Medium (24.60%)
* Total Accepted: 631K
* Total Submissions: 2.6M
* Testcase Example: '[-1,0,1,2,-1,-4]'

Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

The solution set must not contain duplicate triplets.

Example:


Given array nums = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]

思考

乍看题目的时候第一反应是先sort,说明已经步入正轨了。

然而自己最初的尝试是去固定两个数,寻找第三个数。然后根据第三个数去移动两边,结果没能很好处理边界问题。

正确解法的答案是固定一个数,然后去寻找另外两个数,遇到相同数字时候的处理方法,相对就比较直观简单了。

解法

首先进行sort。sort的时间复杂度是O(nlogn). 远远在暴力解法至少两层循环的log(n^3)之下。

sort之后,我们进行循环。对于每个元素sorted[i], 我们使用两边夹逼去寻找符合条件的sorted[left], sorted[right]

注意跳过重复的元素。

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
def three_sum(nums)
sorted = nums.sort
i = 0
j = sorted.length - 1
result = []
for i in 0..sorted.length - 3
next if (i > 0 && sorted[i] == sorted[i-1])
target = 0 - sorted[i]
left = i+1
right = sorted.length - 1
while (left < right)
a = sorted[left]
b = sorted[right]
if (a + b == target)
result << [a,b, sorted[i]].sort
while(sorted[left+1] == a && left < right)
left+=1
end
while(sorted[right-1] == b && left < right)
right -=1
end
left+=1
right-=1
elsif a+b < target
left +=1
else
right -=1
end
end
end
return result
end

Longest Common Prefix

这道题目其实非常简单。之所以要标记起来是因为发现自己很不擅长处理类似的边界。

问题

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

[14] Longest Common Prefix

https://leetcode.com/problems/longest-common-prefix/description/

* algorithms
* Easy (34.02%)
* Total Accepted: 530.8K
* Total Submissions: 1.6M
* Testcase Example: '["flower","flow","flight"]'

Write a function to find the longest common prefix string amongst an array of strings.

If there is no common prefix, return an empty string "".

Example 1:


Input: ["flower","flow","flight"]
Output: "fl"


Example 2:


Input: ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix among the input strings.


Note:

All given inputs are in lowercase letters a-z.

思路

首先对字符串数组进行排序,找到最短的字符串,那么我们知道最长前缀子字符串的长度是不可能超过这个最短字符串长度的。
然后我们就开始遍历,对于最短字符串中的每个元素,我们遍历整个字符串数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def longest_common_prefix(strs)
return "" if strs.empty?
sorted = strs.sort{|a| a.length}
i = 0
while i < sorted[0].length
a = sorted[0][i]
j = 0
while j < strs.length - 1
j+=1
return sorted[0][0...i] if sorted[j][i] != a
end
i += 1
end
return sorted[0]
end

后记

联想到生活中的一些目标,其实关键还是去分析自己缺乏什么解决问题的关键要素。
对症下药而不是盲目叠加自我满足感。

Minimum Window Substring 最小窗口子串

问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[76] Minimum Window Substring  

https://leetcode.com/problems/minimum-window-substring/description/

* algorithms
* Hard (31.68%)
* Total Accepted: 267.2K
* Total Submissions: 841.8K
* Testcase Example: '"ADOBECODEBANC"\n"ABC"'

Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

Example:


Input: S = "ADOBECODEBANC", T = "ABC"
Output: "BANC"


Note:


If there is no such window in S that covers all characters in T, return the empty string "".
If there is such window, you are guaranteed that there will always be only one unique minimum window in S.

解析

据说窗口移动问题是疏通Array各种问题中的关键的关键。

这道Leetcode上难度为hard的题目显然就是传说中的不会做就是100年不会的题目。

看完别人的分析,我们来自己分析一下。

这个题目的核心就是,首先移动右边界,去寻找一个符合条件的字符串,记录下这个字符串的长度,然后移动左边界,直到去掉一个关键的字符,然后再试着移动右边界,去寻找一个比刚刚更短的符合条件的字符串。

详细来说,

首先,我们用一个hash来记录T中各个字符出现的次数。记做hash_t

那么例子中,我们获得的hash_t就是{a=>1, b=>1, c=>1}

接下来我们逐个遍历s中的每个字符,假设当前位置为i。每当我们遇到t中出现的字符,就将hash_t[s[i]]对应地减去1。

hash_t[s[i]]为0的时候,我们知道我们已经找到了符合要求的一个字符,所以我们可以另外用一个cnt,初始值为0,每当hash_t[s[i]]为0,我们就将cnt加上1。
同时,我们将hash_t[s[i]]减去1。

想想一下我们可能遇到hash_t[s[i]] 为负数的情况,但是这个也不要紧,这说明当前字符串s中已经有了多个在t中出现的相同字符。

当cnt等于t的长度,说明我们已经找齐了所有的t中的字符,这个时候可以将当前从左边界到右边界的字符串和目前已经知道的最短符合条件的字符串进行比较。

接下来,移动左边界left。当左边界的字符不在我们hash_t中的时候,我们不断移动左边界。当左边字符在hash_t中,我们将hash_t[s[left]]加上1。并将cnt减去1.
hash_t[s[left]]变为0以上,说明我们又缺乏了s[left],所以需要移动右边界去继续寻找。。。

Ruby 解法

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
def min_window(s, t)
hash_t = {}
t.split("").each do |c|
hash_t[c] ||=0
hash_t[c]+=1
end
cnt = 0
left = 0
min = 2**31 - 1
result = ""
for i in 0..s.length - 1
right = s[i]
if hash_t[right]
hash_t[right] -=1
cnt +=1 if hash_t[right] >= 0
end
while cnt == t.length
if min > i - left + 1
min = i - left + 1
result = s[left...left+min]
end
if hash_t[s[left]]
hash_t[s[left]] +=1
cnt -=1 if hash_t[s[left]] > 0
end
left +=1
end
end
return result
end

反思

刷题的话并不是要发明什么,所以百思不得其解的时候,去看一下答案还是有必要的。

如何把微信上传的M4a语音转换成iphone的闹铃音

背景

想让慧玲教我一下韩语的发音,于是我说你把这两个单词读一遍吧。

然后就有了以下。

哈哈太好听了,决定设置成闹铃~

可是应该怎么办呢?

方法

思路很简单,想方设法把音乐文件倒入itunes就行。

微信会自动把上传的语音文件转换为m4a格式,我们需要把m4a转换成itunes可以识别的格式,比如mp3。

各种意义,ffmpeg是我最喜欢的工具之一。

1
ffmpeg -i Delicious\ House.m4a -ab 256k huiling_alarm.mp3

转换好之后在itunes里面打开,连接上手机sync到手机上的itunes即可。

最后,在闹钟的设置里面,把默认的铃声换成目标铃声。

后话

生活的乐趣在于发现有意义的问题然后用所获取的知识去设计解决。

一筹莫展的LeetCode10 正则表达式匹配

基本上是一筹莫展的题目,果断时间再遇到估计也还是一筹莫展。

题目

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
[10] Regular Expression Matching  

https://leetcode.com/problems/regular-expression-matching/description/

* algorithms
* Hard (25.59%)
* Total Accepted: 333.7K
* Total Submissions: 1.3M
* Testcase Example: '"aa"\n"a"'

Given an input string (s) and a pattern (p), implement regular expression matching with support for '.' and '*'.


'.' Matches any single character.
'*' Matches zero or more of the preceding element.


The matching should cover the entire input string (not partial).

Note:


s could be empty and contains only lowercase letters a-z.
p could be empty and contains only lowercase letters a-z, and characters like . or *.


Example 1:


Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".


Example 2:


Input:
s = "aa"
p = "a*"
Output: true
Explanation: '*' means zero or more of the preceding element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".


Example 3:


Input:
s = "ab"
p = ".*"
Output: true
Explanation: ".*" means "zero or more (*) of any character (.)".


Example 4:


Input:
s = "aab"
p = "c*a*b"
Output: true
Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore, it matches "aab".


Example 5:


Input:
s = "mississippi"
p = "mis*is*p*."
Output: false

解读

基本就是要考虑遇到.*以及*的时候。

举个例子来说,

1
2
s = "mississippi"
p = "mis*is*p*."

我们大可跳过前面不是特殊情况的完全匹配的部分,直到

1
2
s = "mi|ssissippi"
p = "mi|s*is*p*."

因为*可以匹配0到多个前面的字符s。所以,我们可以去试着递归匹配

1
2
3
4
5
6
7
8
9
s = "ssissippi"
p = "is*p*."


s = "sissippi"
p = "is*p*."

s = "issippi"
p = "is*p*."

所以基本流程是

  1. 当p长度为0,检查s是否长度为0,是的话返回true,否则返回false。
  2. 当p的长度为1, 检查s的长度是否为1,如果s长度为1,并且s和p相同亦或者p为”.”,则返回true,否则返回false。
  3. 当p[1]不为*的时候递归匹配s[1..-1] p[1..-1]
  4. 当p[1]为*的时候,这个时候就麻烦了。因为*可以匹配0个到多个p[0],所以我们得做一次循环,在循环中递归匹配。

Ruby 解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def is_match(s, p)
return s.length == 0 if p.length == 0
return s.length == 1 && (s[0] == p[0] || p[0] ==".") if p.length == 1
if p[1] != "*"
return false if s.length == 0
return (s[0] == p[0] || p[0] ==".") && is_match(s[1..-1], p[1..-1])
end
temp = s
while s.length != 0 && (s[0] == p[0] || p[0] == ".")
result = is_match(s[1..-1], p[2..-1])
return true if result == true
s = s[1..-1]
end
return is_match(temp, p[2..-1])
end

后话

不看答案我是真的不会,看了答案我还是懵的。

leetcode6 ZigZag Ruby解法

题目

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
[6] ZigZag Conversion  

https://leetcode.com/problems/zigzag-conversion/description/

* algorithms
* Medium (32.97%)
* Total Accepted: 352.2K
* Total Submissions: 1.1M
* Testcase Example: '"PAYPALISHIRING"\n3'

The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)


P A H N
A P L S I I G
Y I R


And then read line by line: "PAHNAPLSIIGYIR"

Write the code that will take a string and make this conversion given a number of rows:


string convert(string s, int numRows);

Example 1:


Input: s = "PAYPALISHIRING", numRows = 3
Output: "PAHNAPLSIIGYIR"


Example 2:


Input: s = "PAYPALISHIRING", numRows = 4
Output: "PINALSIGYAHRPI"
Explanation:

P I N
A L S I G
Y A H R
P I

解题思路

这道题目虽然属于中级难度,但是其实非常简单。
读清题意之后可以知道,我们可以把字符串按照长度分组。每个组内的元素的行号都可以根据这个元素在每个小组之内的位置推测出来。

以下面的例子来说

1
2
3
4
5
6
s = "PAYPALISHIRING", numRows = 3

result is
P A H N
A P L S I I G
Y I R

首先,我们可以设定一个二维数组result来存放结果。

很显然,我们期待的结果是result = [[P,A,H,N],[A,P,L,S,I,I,G],[Y,I,R]],
这个问题就转换为获取s中的index为i的元素,我们求要把s[i]放入0到numRows的哪个子数组中。

很容易发现,每个|/可以分为一组,比如PAYP, ALIS,HIRI, NG

这个组的长度也很好求,就是两列,第一列和row相当长度,第二列则去掉首位,所以是numRows -2

所以我们可知每个组的长度为2*numRows - 2

假设每个组的长度为split_length, s[i]所在组内的位置positioni%split_length, 这个位置有两种情况

  1. 这个元素在| 上。 这个时候, 且position < numRows, 我们把s[i] 放入 result[position]组中。

  2. 这个元素在/ 上。 这个时候, 且position > numRows, 我们把s[i]放入 result[numRows- 1 - (numRows - 1 - position)] 组中。

解答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# @param {String} s
# @param {Integer} num_rows
# @return {String}
def convert(s, num_rows)
return s if num_rows == 1 || s.length == num_rows
split_length = 2 * num_rows - 2
result = []
for i in 0..s.length-1
position = i % split_length
if (position < num_rows)
result[position] = result[position] || []
result[position] << s[i]
else
result[2* num_rows - position - 2] = result[2* num_rows - position - 2] || []
result[2* num_rows - position - 2] << s[i]
end
end
return result.flatten.join
end

ok, pass

1
2
3
4
➜  java_learning leetcode submit 6.zigzag-conversion.rb
✔ Accepted
✔ 1158/1158 cases passed (68 ms)
[WARN] Failed to get submission beat ratio.

最长回文字符串算法-Manacher’s Algorithm 的Ruby解法

背景

Manacher’s Algorithm 是将最大回文字符串算法的复杂度降低到O(n)的算法。

原题来自LeetCode的第五题。

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
➜  my_blog git:(master) ✗ leetcode show 5
[5] Longest Palindromic Substring

https://leetcode.com/problems/longest-palindromic-substring/description/

* algorithms
* Medium (27.79%)
* Total Accepted: 632.5K
* Total Submissions: 2.3M
* Testcase Example: '"babad"'

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example 1:


Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.


Example 2:


Input: "cbbd"
Output: "bb"

动态规划解法

假设已经有一个判断字符串是否回文的函数, i = 0, j = s.length

  1. 如果这个字符串s已经是回文,则直接返回这个字符串。

  2. 如果这个字符串s不是回文,我们考虑去寻找两个子字符串的最大回文。s[i+1..j], s[i..j-1]

于是有了以下的解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def longest_palindrome(s)
return s if is_palindrome(s)
i = 0
j = s.length - 1
s1 = longest_palindrome(s[i+1..j])
s2 = longest_palindrome(s[i..j-1])
return (s1.length > s2.length ? s1 : s2)
end


def is_palindrome(s)
i = 0
j = s.length - 1
while i < j
return false if s[i] != s[j]
i += 1
j -= 1
end
return true
end

然后提交之后,Leetcode说,不好意思,超时了。。。两年之前通过的解答为啥超时了?

看了一下,testcase从原来的94增加到了103。。。

之前解题时候只图通过,而没仔细想过优化,上网一找,回文问题还是有固定的最优解决方式的。

马拉车算法

马拉车算法太复杂了。不看答案估计一辈子想不出来,光看思路也是十分费解。

我自然是不打算在这里写一遍思路。单纯引用别人已经整理好的东西即可。

比如这位大哥的解说是我最大致能够看懂的。

点击这里

网上大多数文章并没提供Ruby的马拉车算法解法。这里贴一下我根据思路的整理。

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
def longest_palindrome(s)
return s if s.length < 2
s = "#" + s.split('').join("#") + "#"
i = 0
c = 1
j = 2
r = 2
p = []
p[0] = 0
p[1] = 1
while j < s.length
i = 2*c - j
if r - j <= p[i]
p[j] = r - j
while ( s[j + p[j] + 1] == s[j - p[j] - 1])
p[j]+=1
end
if p[j] + j > r
c = j
r = j + p[j]
end
else
p[j] = p[i]
end
j = j + 1
end
max = p.max
max_index = p.index(max)
return s[max_index-max..max_index+max].gsub("#", "")
end
1
2
3
4
➜  ruby leetcode submit 5.longest-palindromic-substring.rb
✔ Accepted
✔ 103/103 cases passed (88 ms)
[WARN] Failed to get submission beat ratio.

OK, 提交成功。

后话

最近又开始刷题了,啊哈啊青春。

她们

(本故事纯属虚构)

“你还在东京吗? 我来旅游了,现在在涩谷,下班的话一起吃个饭呗。”

盯着RabbitMQ里面堵塞的一百八十万条Message一筹莫展的我,被突然弹起的微信消息打断。

手指停留在输入框上,想要回复些什么,
脑海里却浮现不出这个人是谁。

下意识去翻看以前的聊天记录却发现换手机的这两年来完全没有说过一句话。

昵称xyk,头像白纸一张,性别保密,朋友圈只开放三天,当然看过去就是空空如也。

大学时代的同学?高中同学?直接问本人大概也是失礼吧,被manager喊进会议室之前,匆匆忙忙回复了个“哦”字,就把这回事忘了。

下班之后几乎已经走到车站的检票口,又收到了xyk的消息。

“我在车站这里有个车厢和小狗像的这里,你还要多久?”

这才想起来下午有那么两句对话之后漫不经心被理解成了晚上要一起吃饭了。

可是,你是谁呀?

等反应过来不知不觉坐上了和回家相反的方向,走出车站门口的时候头上已经是大盛堂书店外面罗拉捧着比特币的广告牌了。

“学长,在这里!” 是个女生的声音,却看到个小帅的眼睛男像我招手。

似曾相识。该是大学里的后辈? 经常一起玩的后辈也就那么几个为什么我对眼前这位帅哥一点印象都没有。

就在这时,背后被猛拍了一下。回头的一瞬间,

脸上的汗珠和车站的喧嚣瞬间凝固住了,下意识想揉一下眼睛却被眼镜框狠狠地刮了一下。

是她。

和很多年前一模一样。

碎花布裙和马尾辫,垫着脚尖比我高那么一点的瘦瘦的身段,下手拍人还是那么狠。

上大学的时候,和她的冲突从未断过。

从刚开始不熟悉的时候,硬要死皮赖脸在食堂挤在一桌吃饭被赶走,到后来故意路过她们宿舍门口的时候,看见她穿着吊带背心吃雪糕的样子,险被砸中花盆。

手机还不是很流行的时候,宿舍里都挂着一个电话机,总是她第一个接电话,刚说完“喂”就被挂断的次数也是不计其数。

眼前的男生大概是她的现任男友吧,据说是同校后辈,不是那么面熟。却感觉很是般配。

已经不记得晚上吃的是哪家店的什么东西,味道怎么样了。她的男友很大方地请了客。
只是吃东西的时候聊起以前的事情她又陷入了一贯的霸道和自豪。

“哈哈我有重要消息宣布!” 她的脸上是酒后的红晕。

她拿出手机,翻开相册,一排婚纱照映入眼帘。新娘洁白的婚纱和新郎俊美的西装。她捧着一束花,站在新娘的旁边,他的男友站在了新郎的旁边。

“看吧,我再也不用当护花使者了!” 她笑着说道。

新娘幸福的微笑和新郎自信满满的笑容看起来是那么和谐,那么美好,那么让人憧憬。

然而,我始终不敢看一眼新娘的眼睛。

大概是怕在手机屏幕的反射里看到自己现在的样子。

(完)

难道大家都没有发现OS 10.15下Chrome76的豆腐块吗

背景

先讲一个笑话。

第一反应是什么?

什么福利网站吗?

这个是github上一个中文repo的readme的第一二行。

原文是“一些高质量电子书资源分享”

这些变成方块无法显示的文字成为豆腐块,仔细对照可以发现豆腐块里的文字都是简体字特有的文字。

这个是为什么?

打开某中文网页,发现完全没有任何豆腐块。

这个是OS的问题吗?

用safari打开同样网站,简体中文显示也完全没问题。

那这个是chrome的问题咯?

用OS10.13下的chrome76打开同样网站,简体中文显示也是没有问题。

那就是chrome76和OS 10.15的兼容性问题了。

解决方法

OS10.15本来就是未公开的beta版本,chrome有类似bug可能也算正常不过。如果是自己host的网站,可以检查网页的lang设定。将默认缺失的设定加上lang="zh-cn"即可。

如果是别人的网站呢?

hmm,我也不知道。

我的SMTP服务为什么挂了

背景

今天打开Mailer的邮箱,发现很久以前给人回复的邮件静静地躺在发送失败的草稿箱里。打开发送,提示输入邮箱密码却怎么也发不出去。

还好我要回复的只是帮人内推的简历,也不知道发我简历的那位哥们会不会恨我。
要是一封情书可能你就真的直到别人快结婚了也不知道自己当年为什么被无视了是吧。

当然说到底,发送邮件有问题肯定是要去修复的。谁让我自架邮件服务器自找麻烦呢。
(简单算一笔帐的话,这个邮箱价值不菲。不仅包含每年域名的更新费7000大洋,还包括每个月的服务器费用1000大洋。)

问题排查

首先得去找验证失败的Log。

1
tailf /var/log/mail.log

试着去登陆等待后台滚动出log来。

1
2
3
Aug  1 23:39:22 bocchi postfix/smtpd[17310]: warning: SASL authentication failure: cannot connect to saslauthd server: No such file or directory
Aug 1 23:39:22 bocchi postfix/smtpd[17310]: warning: SASL authentication failure: Password verification failed
Aug 1 23:39:22 bocchi postfix/smtpd[17310]: warning: xxxxx[xxxx.xxxx.xxxx.xxxx]: SASL PLAIN authentication failed: generic failure

Postfix 验证的时候使用到了Saslauthd。看问题应该是Postfix找不到SASL的进程文件目录。

那么,Saslauthd在跑吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
sudo systemctl status saslauthd

● saslauthd.service - LSB: saslauthd startup script
Loaded: loaded (/etc/init.d/saslauthd; bad; vendor preset: enabled)
Active: active (running) since Mon 2018-12-03 13:22:36 JST; 7 months 28 days ago
Docs: man:systemd-sysv-generator(8)
Process: 999 ExecStart=/etc/init.d/saslauthd start (code=exited, status=0/SUCCESS)
CGroup: /system.slice/saslauthd.service
├─1110 /usr/sbin/saslauthd -a pam -c -m /var/spool/postfix/var/run/saslauthd -n 5
├─1111 /usr/sbin/saslauthd -a pam -c -m /var/spool/postfix/var/run/saslauthd -n 5
├─1112 /usr/sbin/saslauthd -a pam -c -m /var/spool/postfix/var/run/saslauthd -n 5
├─1113 /usr/sbin/saslauthd -a pam -c -m /var/spool/postfix/var/run/saslauthd -n 5
└─1114 /usr/sbin/saslauthd -a pam -c -m /var/spool/postfix/var/run/saslauthd -n 5

好像也没啥问题。至少,我敢确定以前我是可以好好发送邮件的。

谷歌了一下类似问题,貌似可以归结到postfix在chroot下运行的时候,会去寻找/var/spool/postfix/var/run/saslauthd。而在非chroot的情况下会去寻找/var/run/saslauthd

于是去查看postfix的config。

1
2
smtp inet n - y - - smtpd
`

y代表chroot模式。是我眼花了吗? 那岂不是没有任何问题,并且/var/spool/postfix/var/run/saslauthd 也是存在的。

抱着死马当活马医的心态,建立一下从/var/run/saslauthd/var/spool/postfix/var/run/saslauthd的symlink。

再试着发送邮件。”刷~”地一声,如同十年的便秘一样瞬间发送成功了。

继续谷歌,看到很多人抱怨说postfix不管怎么配置chroot总是默认不使用,于是我也懒得追究了。

事情的真相

从一开始配置postfix的时候,应该是抄了哪边的manual。于是神使鬼差使用了ln -s /var/spool/postfix/var/run/saslauthd /var/run/saslauthd

然而,现在使用的服务器的运营商中间因为机房迁移断电重启过一次,导致我的sysmlink失效了。

啊sysmlink重启还能失效? 对的,因为这个目录是/var/run。。。

最近我又收到服务器运营商的maint邮件说要有宕机重启了。这次我应该知道怎么做了。