Zhuanli&Blog


  • 首页

  • 标签

  • 分类

  • 归档

leetcode 315. 计算右侧小于当前元素的个数

发表于 2018-07-18 | 分类于 leetcode

给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。

示例:

输入: [5,2,6,1]
输出: [2,1,1,0] 
解释:
5 的右侧有 2 个更小的元素 (2 和 1).
2 的右侧仅有 1 个更小的元素 (1).
6 的右侧有 1 个更小的元素 (1).
1 的右侧有 0 个更小的元素.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import bisect
class Solution:
def countSmaller(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
sorted_list = []
res = []
for num in nums[::-1]:
pos = bisect.bisect_left(sorted_list,num)
res.append(pos)
bisect.insort(sorted_list,num)
return res[::-1]

leetcode 316. Remove Duplicate Letters

发表于 2018-07-17 | 分类于 leetcode

Given a string which contains only lowercase letters, remove duplicate letters so that every letter appear once and only once. You must make sure your result is the smallest in lexicographical order among all possible results.

Example 1:

Input: "bcabc"
Output: "abc"

Example 2:

Input: "cbacdcbc"
Output: "acdb"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution:
def removeDuplicateLetters(self, s):
"""
:type s: str
:rtype: str
"""
res = [0]*26
pos = 0#the smallest s[i]
for i in range(len(s)):
tmp = ord(s[i])-97
res[tmp] += 1
for i in range(len(s)):
if s[pos] > s[i]:pos = i
res[ord(s[i])-97] -= 1
if res[ord(s[i])-97] == 0:
break
return '' if len(s) == 0 else s[pos] + self.removeDuplicateLetters(s[pos+1:].replace(s[pos],''))

a clear solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def removeDuplicateLetters(self, s):
"""
:type s: str
:rtype: str
"""
rindex = {c: i for i, c in enumerate(s)}
result = ''
for i, c in enumerate(s):
if c not in result:
while c < result[-1:] and i < rindex[result[-1]]:
result = result[:-1]
result += c
return result

守护进程

发表于 2018-07-16 | 分类于 linux

守护进程

守护进程介绍

在Linux 或者 UNIX 操作系统中在系统的引导的时候会开启很多服务,这些服务就叫作守护进程 。
守护进程是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件 。
由于在 Linux 中,每 个系统与用户进行交流的界面称为终端,每 个从此终端运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关
闭时,相应的进程 会自动关闭 ,但是守护进程却能够突破这种限制,它从被执行时开始运转,直到整个系统关闭时才退出 ,如果想让某个进程不因为用户或终端或其他地变化而受到关闭
,那么就必须把这个进程变成一个守护进程。
一个简单的守护进程的步骤如下所述:

  1. 创建子进程,父进程退出
  2. 调用setsid函数在子进程中创建新会话。
    在建守护进程时为什么要调用setsid函数呢?由于创建守护进程的第1 步调用fork 函数创建子进程,再将父进程退出 由于在第1步调用了 fork 函数时,子进程全盘拷贝
    了父进程的会话期 进程组 控制终端等,虽然父进程退出了,但 话期、进程组 控制终
    端等并没有改变,因此,还不是真正意义上的独立 setsid函数能够使进程完全独立出来,
    从而摆脱其他进程的控制。
  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
31
32
33
34
35
36
37
38
39
40
41
42
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#define MAXFILE 65535
int main()
{
pid_t pc;
int i,fd,len;
const char *buf = "this is a Daemon\n";
len = strlen(buf);
pc = fork();
if(pc < 0)
{
printf("error fork\n");
exit(1);
}else if(pc > 0){
exit(0);
}//1
setsid();//2
chdir("/");//3
umask(0);//4
for(i = 0;i < MAXFILE;i++)
{
close(i);
}//5
while(1){
if((fd = open("/tmp/daemon.log",O_CREAT|O_WRONLY|O_APPEND,0600)) <0)
{
perror("open");
exit(1);
}
write(fd,buf,len+1);
close(fd);
sleep(10);
}
return 0;
}

leetcode 318. 最大单词长度乘积

发表于 2018-07-16 | 分类于 leetcode

给定一个字符串数组 words,找到 length(word[i]) * length(word[j]) 的最大值,并且这两个单词不含有公共字母。你可以认为每个单词只包含小写字母。如果不存在这样的两个单词,返回 0。

示例 1:

输入: ["abcw","baz","foo","bar","xtfn","abcdef"]
输出: 16 
解释: 这两个单词为 "abcw", "xtfn"。

示例 2:

输入: ["a","ab","abc","d","cd","bcd","abcd"]
输出: 4 
解释: 这两个单词为 "ab", "cd"。

示例 3:

输入: ["a","aa","aaa","aaaa"]
输出: 0 
解释: 不存在这样的两个单词。
  • my solution (slower)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Solution:
    def maxProduct(self, words):
    """
    :type words: List[str]
    :rtype: int
    """
    d = {}
    for w in words:
    d[w] = set(w)

    ans = 0
    for i in range(len(words)-1):
    for j in range(i+1, len(words)):
    if not (d[words[i]] & d[words[j]]):
    ans = max(ans, len(words[i]) * len(words[j]))
    return ans
  • a faster solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def maxProduct(self, words):
"""
:type words: List[str]
:rtype: int
"""
d = {}
for word in words:
mask = 0
for char in set(word):
mask |= (1 << (ord(char) - 97))
d[mask] = max(d.get(mask, 0), len(word))

return max([d[x] * d[y] for x in d for y in d if not x & y] or [0])

leetcode 319. 灯泡开关

发表于 2018-07-16 | 分类于 leetcode

初始时有 n 个灯泡关闭。 第 1 轮,你打开所有的灯泡。 第 2 轮,每两个灯泡你关闭一次。 第 3 轮,每三个灯泡切换一次开关(如果关闭则开启,如果开启则关闭)。第 i 轮,每 i 个灯泡切换一次开关。 对于第 n 轮,你只切换最后一个灯泡的开关。 找出 n 轮后有多少个亮着的灯泡。

示例:

输入: 3
输出: 1 
解释: 
初始时, 灯泡状态 [关闭, 关闭, 关闭].
第一轮后, 灯泡状态 [开启, 开启, 开启].
第二轮后, 灯泡状态 [开启, 关闭, 开启].
第三轮后, 灯泡状态 [开启, 关闭, 关闭]. 

你应该返回 1,因为只有一个灯泡还亮着。

思路:由题意可以知道,一个开关i被拨动的次数就是i的约数的个数,而一个数的约数总是成双成对出现的,除非它是一个完全平方数。约数个数为奇数的情况下,灯是开着的,所以题目就变成求1-n中完全平方数的数目。

1
2
3
4
5
6
7
8
import math
class Solution(object):
def bulbSwitch(self, n):
"""
:type n: int
:rtype: int
"""
return int(math.sqrt(n))

leetcode 321. 拼接最大数

发表于 2018-07-13 | 分类于 leetcode

给定长度分别为 m 和 n 的两个数组,其元素由 0-9 构成,表示两个自然数各位上的数字。现在从这两个数组中选出 k (k <= m + n) 个数字拼接成一个新的数,要求从同一个数组中取出的数字保持其在原数组中的相对顺序。

求满足该条件的最大数。结果返回一个表示该最大数的长度为 k 的数组。

说明: 请尽可能地优化你算法的时间和空间复杂度。

示例 1:

输入:
nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
k = 5
输出:
[9, 8, 6, 5, 3]

示例 2:

输入:
nums1 = [6, 7]
nums2 = [6, 0, 4]
k = 5
输出:
[6, 7, 6, 0, 4]

示例 3:

输入:
nums1 = [3, 9]
nums2 = [8, 9]
k = 3
输出:
[9, 8, 9]

思路:

  1. 从nums1取i个,从nums2取k-i个
  2. 取最大的k数字数组
  3. 比较哪个数组大
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution(object):
def maxNumber(self, nums1, nums2, k):

def prep(nums, k):
drop = len(nums) - k
out = []
for num in nums:
while drop and out and out[-1] < num:
out.pop()
drop -= 1
out.append(num)
return out[:k]

def merge(a, b):
return [max(a, b).pop(0) for _ in a+b]

return max(merge(prep(nums1, i), prep(nums2, k-i))
for i in range(k+1)
if i <= len(nums1) and k-i <= len(nums2))

进程间通信

发表于 2018-07-12 | 分类于 linux

进程间通信

常用的进程间通信方式包括:管道、 消息队列、共享
内存、信号量、套接字等 。其中,前面 4种主要用于同1 台机器上的进程间通信,而套接字
则主要用于不同机器之间的网络通信 。

管道

管道是 Linux 支持的最初
UNIX IPC 形式之一,具有以下特点:

  1. 数据只能由一个进程流向另一个进程(其中一个读管道, 个写管道);如果要进行
    双工通信,则需要建立两个管道
  2. 管道只能用于父子进程或者兄弟进程间通信,也就是说管道只能用于具有亲缘关系的进程间通信

利用管道进行通信:

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
int fd[2];
pid_t pid;
char buf[256];
int returned_count;
pipe(fd);//创建无名管道
pid = fork();//创建子进程
if(pid < 0)
{
printf("error in fork\n");
exit(1);
}
else if(pid == 0)
{
//child process
printf("in child process...\n");
close(fd[0]);//child process write to parent process,close read pipe
write(fd[1],"hello world",strlen("hello world"));
exit(0);
}else{
//parent process
close(fd[1]);
returned_count = read(fd[0],buf,sizeof(buf));
printf("%d bytes of data received from child process:%s\n",returned_count,buf);
}
return 0;
}

消息队列

消息队列用于运行于同一台机器上的进程间通信,它和管道很相似,是一个在系统内核
中用来保存消息的队列,它在系统内核中是以消息链表的形式出现 消息链表中节点的结构
msg 声明

共享内存

共享内存就是允许两个不相关的进程访问同 1个逻辑内存。 共享 内存是在两
个正在运行的进程之间共享和传递数据的非常有效的方式。 不同进程之间共享的内存通
常安排在同1 段物理内存中。 进程可以将同一段共享内存连接到它们 自己 的地址空间中,所
有进程都可以访问共享内存中的地址。
而如果某个进程向共享内存写入数据,所做的改动将影响共享
内存的任何其他进程。
不过,共享内存并未提供同步机制,所以通常需要其他的机制来同步对共享内存的访问。
利用共享内存进行通信:
producer.cpp

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/shm.h>
#include "shm_com.h"
int main()
{
int shmid;
shmid = shmget((key_t)1234,sizeof(struct shared_use_st),0666|IPC_CREAT);
if(shmid == -1)
{
fprintf(stderr,"shmget failed\n");
exit(EXIT_FAILURE);
}
void *shared_memory = NULL;
shared_memory = shmat(shmid,NULL,0);
if(shared_memory == (void *)-1)
{
fprintf(stderr,"shmat failed\n");
exit(EXIT_FAILURE);
}
printf("memory attached at %X\n",(long)shared_memory);
struct shared_use_st *shared_stuff;
shared_stuff = (struct shared_use_st*)shared_memory;
int running = 1;
char buffer[TEXT_SZ];
while(running)
{
while(shared_stuff->written == 1)
{
sleep(1);
printf("waiting for client...\n");
}
printf("enter some text: ");
fgets(buffer,TEXT_SZ,stdin);
strncpy(shared_stuff->text,buffer,TEXT_SZ);
shared_stuff->written = 1;
if(strncmp(shared_stuff->text,"end",3) == 0)
{
running = 0;
}
}
if(shmdt(shared_memory) == -1)
{
fprintf(stderr,"shmdt failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}

consumer.cpp

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/shm.h>
#include "shm_com.h"
int main()
{
int shmid;
srand((unsigned int)getpid());
shmid = shmget((key_t)1234,sizeof(struct shared_use_st),0666|IPC_CREAT);
if(shmid == -1)
{
fprintf(stderr,"shmget failed\n");
exit(EXIT_FAILURE);
}
void *shared_memory = NULL;
shared_memory = shmat(shmid,NULL,0);
if(shared_memory == (void *)-1)
{
fprintf(stderr,"shmat failed\n");
exit(EXIT_FAILURE);
}
printf("memory attached at %X\n",(long)shared_memory);
struct shared_use_st *shared_stuff;
shared_stuff = (struct shared_use_st*)shared_memory;
shared_stuff->written = 0;
int running = 1;
while(running)
{
if(shared_stuff->written)
{
printf("you wrote:%s",shared_stuff->text);
sleep(rand()%4);
shared_stuff->written = 0;
if(strncmp(shared_stuff->text,"end",3) == 0)
{
running = 0;
}
}
}
if(shmdt(shared_memory) == -1)
{
fprintf(stderr,"shmdt failed\n");
exit(EXIT_FAILURE);
}
if(shmctl(shmid,IPC_RMID,0) == -1)
{
fprintf(stderr,"shmctl failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}

头文件shm_com.h

1
2
3
4
5
6
#define TEXT_SZ 2048
struct shared_use_st{
int written;
char text[TEXT_SZ];
};
#define NULL (void *)0

信号量

多线程同步中提及了信号 ,但用于多线程同步的信号量是
POSIX 信号 ,而此信号量是 SYSTEM 信号 ,本质上说这两种都是用户态进
程可以使用的信号量 。
共享内存是进程间通信的最快的方式,但是共享内存的同步问题自身无法解决(即进程该何时去共享内存取得数据,而何时不能取),但用信号量即可轻易解决这个问题。

leetcode 322. 零钱兑换

发表于 2018-07-12 | 分类于 leetcode

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

示例 1:

输入: coins = [1, 2, 5], amount = 11
输出: 3 
解释: 11 = 5 + 5 + 1

示例 2:

输入: coins = [2], amount = 3
输出: -1

说明:
你可以认为每种硬币的数量是无限的。

  • dp solution o(n^2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
dp = [0]
for money in range(1,amount+1):
dp.append(float('inf'))
for coin in coins:
if money-coin >= 0:
dp[-1] = min(dp[-1],dp[money - coin]+1)
if dp[-1] == float('inf'):return -1
return dp[-1]
  • dfs solution o(n*amount/coins[i])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
if amount == 0: return 0
coins.sort(reverse=True)
self.best = float('inf')
def dfs(start, coins, amount, cur):
if start == len(coins)-1:
if amount%coins[start] == 0:
self.best = min(self.best, cur + amount/coins[start])
else:
for i in range(amount/coins[start], -1, -1):
if cur + i >= self.best: break
dfs(start+1, coins, amount-i*coins[start], cur+i)
dfs(0, coins, amount, 0)
return self.best if self.best != float('inf') else -1

leetcode 324. 摆动排序 II

发表于 2018-07-11 | 分类于 leetcode

给定一个无序的数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]… 的顺序。

示例 1:

输入: nums = [1, 5, 1, 1, 6, 4]
输出: 一个可能的答案是 [1, 4, 1, 5, 1, 6]

示例 2:

输入: nums = [1, 3, 2, 2, 3, 1]
输出: 一个可能的答案是 [2, 3, 1, 3, 1, 2]
1
2
3
4
5
import time
def wiggleSort(nums):
nums.sort()
half = len(nums[::2]) - 1
nums[::2], nums[1::2] = nums[half::-1], nums[:half:-1]

leetcode 327. 区间和的个数

发表于 2018-07-10 | 分类于 leetcode

给定一个整数数组 nums,返回区间和在 [lower, upper] 之间的个数,包含 lower 和 upper。
区间和 S(i, j) 表示在 nums 中,位置从 i 到 j 的元素之和,包含 i 和 j (i ≤ j)。

说明:
最直观的算法复杂度是 O(n2) ,请在此基础上优化你的算法。

示例:

输入: nums = [-2,5,-1], lower = -2, upper = 2,
输出: 3 
解释: 3个区间分别是: [0,0], [2,2], [0,2],它们表示的和分别为: -2, -1, 2。
  • O(n*(upper-lower))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution(object):
def countRangeSum(self, nums, lower, upper):
cnt = {0:1}
ans = 0
cursum = 0
for num in nums:
cursum += num
for d in range(lower,upper+1):
if cursum-d in cnt:
ans += cnt[cursum-d]
if cursum in cnt:
cnt[cursum] += 1
else:
cnt[cursum] = 1
return ans
  • O(nlog(n)),mergesort
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
int mergeSort(vector<long>& sum, int lower, int upper, int low, int high)
{
if(high-low <= 1) return 0;
int mid = (low+high)/2, m = mid, n = mid, count =0;
count =mergeSort(sum,lower,upper,low,mid) +mergeSort(sum,lower,upper,mid,high);
for(int i =low; i< mid; i++)
{
while(m < high && sum[m] - sum[i] < lower) m++;
while(n < high && sum[n] - sum[i] <= upper) n++;
count += n - m;
}
inplace_merge(sum.begin()+low, sum.begin()+mid, sum.begin()+high);
return count;
}

int countRangeSum(vector<int>& nums, int lower, int upper) {
int len = nums.size();
vector<long> sum(len + 1, 0);
for(int i =0; i< len; i++) sum[i+1] = sum[i]+nums[i];
return mergeSort(sum, lower, upper, 0, len+1);
}
};
1…91011…20

zhuanli

194 日志
9 分类
41 标签
GitHub
© 2018 — 2019 zhuanli
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.4