800. Similar RGB Color
class Solution {
int getn(int k){
return (k+8)/17;
}
string strd(int k){
char ret[3];
if(k<=9){
ret[1]=char(k+'0');
ret[0]=char(k+'0');
}
else{
ret[0]=char(k-10+'a');
ret[1]=char(k-10+'a');
}
ret[2]='\0';
return string(ret);
}
public:
string similarRGB(string color) {
string a=string("#");
for(int i=1;i<=5;i+=2){
int y=getn(strtoul(color.substr(i,2).c_str(),0,16));
// printf("%d\n",y);
a+=strd(y);
}
return a;
}
};
以上是我的解法,网上搜了一下rbg string 转int的方式
归一的时候使用了四舍五入的技巧
801. Minimum Swaps To Make Sequences Increasing
动态规划
在每一个位置分别记录两个状态 ,在这个 位置换 和在这个位置不换得到的最小操作数(当然前提是可以)
考虑倒 上一个位置就有两种可能, 那么一共有四种递推可能,地推方程略
class Solution {
public:
int minSwap(vector& A, vector& B) {
const int maxn=200000;
int len=A.size();
int t=1,n=0;
for(int i=1;iA[i-1]&&B[i]>B[i-1]){
tt=1;
nn=1;
}
if(A[i]>B[i-1]&&B[i]>A[i-1]){
tn=1;
nt=1;
}
n=min(tn?(pt):maxn,nn?(pn):maxn);
t=min((tt)?(pt+1):(maxn),(nt)?(pn+1):(maxn));
}
return min(t,n);
}
};
下面是一个简介的py 版本大意相同
def minSwap(self, A, B):
"""
:type A: List[int]
:type B: List[int]
:rtype: int
"""
n = len(A)
pre = [0, 1]
for i in range(1, n):
cur = [sys.maxsize, sys.maxsize]
if A[i]>A[i-1] and B[i]>B[i-1]:
cur[0] = min(cur[0], pre[0])
cur[1] = min(cur[1], pre[1]+1)
if A[i]>B[i-1] and B[i]>A[i-1]:
cur[0] = min(cur[0], pre[1])
cur[1] = min(cur[1], pre[0]+1)
pre = cur
return min(pre)
802. Find Eventual Safe States
tarjan 算法的变形。
总而言之,我们定义一个bad 的连通分量: 如果他的 规模大于1 或者有子环或者通向其他bad的连通分量则为bad 联通分量 ,问非bad的联通分量有多少个
在经典的tarjan 算法中,判断一个下一个节点是否是自己(标机bad)
遍历到 没有vis 但是dfn 确有的节点时要注意( 因为一次深搜有可能无法解决所有的节点) 我们需要选择多个入口,就出现了这种问题
然后发现一个强连通分量的时候判断规模 是否大于1个 如果大于 那么这个强连通分量就标记为bad
下面是代码
class Solution {
int cnt,top;
int dfn[10002];
int low[10002];
int stack[10002];
int bad[10002];
int vis[10002];
int dfs(int k,vector >&graph2){
if(vis[k])return low[k];
dfn[k]=++cnt; //时间戳
low[k]=dfn[k]; //扩展戳
stack[top++]=k; //栈中节点
vis[k]=1; //栈中标记
int len=graph2[k].size();
for(int i=0;i eventualSafeNodes(vector >& graph) {
vector ans;
int len=graph.size();
cnt=0,top=0;
ans.clear();
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(bad,0,sizeof(bad));
memset(vis,0,sizeof(vis));
for(int i=0;i
官方Solution
先找到没有出度的点 标记为safe
然后一次处理这些safe 的点 从反向图中找到这些safe 点的上家,如果上家
class Solution(object):
def eventualSafeNodes(self, graph):
N = len(graph)
safe = [False] * N
graph = map(set, graph) #从list 模式转换到set 模式
rgraph = [set() for _ in xrange(N)] 为反向图创建 list of set
q = collections.deque() 处理队列
for i, js in enumerate(graph):
if not js:
q.append(i) #没有出度的节点先进入队列 等待处理
for j in js:
rgraph[j].add(i) #创建反向图
while q:
j = q.popleft() # 取出一个安全的节点
safe[j] = True # 标记为safe
for i in rgraph[j]: #找到他所有的上家
graph[i].remove(j) #在正常图中移除 上家连接他的关系
if len(graph[i]) == 0: #如果上家移除了之后没有其余下家了 就认为上家同样安全
q.append(i)
return [i for i, v in enumerate(safe) if v]
这个思路简介明了 直奔主题, 确实是好思路
官方Solution2 暴力深搜
entry 标记为gray
exit 就标记为black 没有访问就是white
实际上这个流程非常实用,我们进行少许的修改
我们认为如果一个节点的出节点 连接了任意那怕一个gray我们就认为他是gray,反之则标记为gray
class Solution(object):
def eventualSafeNodes(self, graph):
WHITE, GRAY, BLACK = 0, 1, 2
color = collections.defaultdict(int)
def dfs(node):
if color[node] != white:
return color[node] == BLACK
color[node] = GRAY
for nei in graph[node]:
if color[nei] == BLACK:
continue
if color[nei] == GRAY or not dfs(nei):
return False
color[node] = BLACK
return True
return filter(dfs, range(len(graph)))
803. Bricks Falling When Hit
受过启发的naive 思路先把所有的cut 点都去掉 然后做一遍深搜 将safe的点标记出来
从尾到头依次加入cut 点,每加入一个cut 就在那个cut周围做一次dfs 但是bug 是明显的
官方Solution
倒叙加入利用并查集的实现
并查集的经典操作
class DSU:
def __init__(self, R, C):
#R * C is the source, and isn't a grid square
self.par = range(R*C + 1)
self.rnk = [0] * (R*C + 1)
self.sz = [1] * (R*C + 1)
def find(self, x): #经典的并查集操作,
# if par[x] !=x
# par[x]=find(par[x])
# return par[x]
if self.par[x] != x:
self.par[x] = self.find(self.par[x])
return self.par[x]
def union(self, x, y):
xr, yr = self.find(x), self.find(y)
if xr == yr: return
if self.rnk[xr] < self.rnk[yr]:
xr, yr = yr, xr
if self.rnk[xr] == self.rnk[yr]:
self.rnk[xr] += 1
## 保证rnk[xr] 稍大一点
self.par[yr] = xr
self.sz[xr] += self.sz[yr]
def size(self, x):
return self.sz[self.find(x)]
def top(self):
# Size of component at ephemeral "source" node at index R*C,
# minus 1 to not count the source itself in the size
return self.size(len(self.sz) - 1) - 1
class Solution(object):
def hitBricks(self, grid, hits):
R, C = len(grid), len(grid[0]) #gird的行和 列
def index(r, c): #索引 index的函数
return r * C + c
def neighbors(r, c): #神奇的操作,生成邻居器
for nr, nc in ((r-1, c), (r+1, c), (r, c-1), (r, c+1)):
if 0 <= nr < R and 0 <= nc < C:
yield nr, nc
A = [row[:] for row in grid] 我感觉,就是grid的拷贝???
for i, j in hits: #将相应的cut 置零
A[i][j] = 0
dsu = DSU(R, C)
for r, row in enumerate(A):
for c, val in enumerate(row): #枚举 处理后图 的节点
if val: #如果为1
i = index(r, c)
if r == 0:
dsu.union(i, R*C) #如果是第一行,就union 到假想节点RC
if r and A[r-1][c]:
dsu.union(i, index(r-1, c)) #如果他的下侧有值 ,就union 到一起
if c and A[r][c-1]:
dsu.union(i, index(r, c-1)) #如果他的上侧有值 , 就union 到一起
ans = []
for r, c in reversed(hits): #倒叙 枚举 可算找到了,倒叙枚举用reversed
pre_roof = dsu.top() #查照总共有多少个节点
if grid[r][c] == 0: #如果在原图中就是空 直接就是0好了
ans.append(0)
else:
i = index(r, c)
for nr, nc in neighbors(r, c):
if A[nr][nc]:
dsu.union(i, index(nr, nc)) #枚举所有的邻居,和邻居union
if r == 0:
dsu.union(i, R*C) #如果是roof 节点,还要和假想节点union
A[r][c] = 1
ans.append(max(0, dsu.top() - pre_roof - 1)) #最后输出前后的差异
return ans[::-1]