ARTS第十周
ARTS是什么?
Algorithm:每周至少做一个leetcode的算法题;
Review:阅读并点评至少一篇英文技术文章;
Tip/Techni:学习至少一个技术技巧;
Share:分享一篇有观点和思考的技术文章。
Algorithm
题目:20. Valid Parentheses
解题思路
1.根据题意需要进行括号配对,当遇到左括号的时候需要存起来,以便遇到右括号的时候去取出来进行配对;当遇到右括号的时候就直接去和保存的左括号进行配对。
2.根据配对的特性我们采用栈这种数据结构来保存左括号。
3.因为存在多组括号()、[]、{},所有需要用一个map来保存每组括号的对应关系。因为我们会根据右括号去取左括号,所以以右括号为key,左括号为value放入map。
代码
public boolean isValid(String s) {
//定义好括号
Map<Character, Character> parentheses = new HashMap<>();
parentheses.put('}', '{');
parentheses.put(']', '[');
parentheses.put(')', '(');
//保存左括号的栈
Stack stack = new Stack();
for (char c : s.toCharArray()) {
//如果是右括号,去栈中弹出一个元素做比较
if (!parentheses.containsKey(c)) {
stack.push(c);
} else if (stack.empty() || !stack.pop().equals(parentheses.get(c))) {
//如果是左括号,压入栈中
return false;
}
}
return stack.isEmpty();
}
Review
java并发同步工具之CountDownLatch
CountDownLatch是一个并发同步工具,它允许一个或多个线程等待一组操作完成。
CountDownLatch可以使用参数count初始化。wait方法会阻塞直到当前count变为0通过调用countDown方法,在那之后,所有等待的线程被释放,await之后的调用立即返回。这是一次性现象,即count不能被重置。如果你需要count可重置的版本,考虑使用CyclicBarrier。
CountDownLatch是一个多功能同步工具,能被用于多种用途。一个被初始化为count=1的CountDownLatch可以用作简单的开关或门:所有调用await方法的线程等待在门口直到它被一个调用countDown的线程打开为止。被初始化为count=N的CountDownLatch能使一个线程等待其他N个线程完成一些动作或者一些动作完成N次。
CountDownLatch一个有用的属性是它不要求调用countDown的线程等待count变为0,它只阻止调用了await方法的线程等待直到所有线程通过。
例子:这里是一对类,其中一组worker线程使用两个countdown latches:
- 第一个是一个开始信号,它阻止worker执行直到dirver准备好让他们继续执行。
- 第二个是一个完成信号,它允许driver等待所有worker工作完成。
class Driver { // ...
void main() throws InterruptedException {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N);
for (int i = 0; i < N; ++i) // create and start threads
new Thread(new Worker(startSignal, doneSignal)).start();
doSomethingElse(); // don't let run yet
startSignal.countDown(); // let all threads proceed
doSomethingElse();
doneSignal.await(); // wait for all to finish
}
}
class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
public void run() {
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork() { ... }
}
另一个典型的应用是分割一个问题为N个部分,用Runnable描述每个部分,执行该部分并对latch进行count down,并将所有Runnables排队到Executor,当所有子部分完成的时候,协调线程也将继续执行下去。
class Driver2 { // ...
void main() throws InterruptedException {
CountDownLatch doneSignal = new CountDownLatch(N);
Executor e = ...
for (int i = 0; i < N; ++i) // create and start threads
e.execute(new WorkerRunnable(doneSignal, i));
doneSignal.await(); // wait for all to finish
}
}
class WorkerRunnable implements Runnable {
private final CountDownLatch doneSignal;
private final int i;
WorkerRunnable(CountDownLatch doneSignal, int i) {
this.doneSignal = doneSignal;
this.i = i;
}
public void run() {
try {
doWork(i);
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork() { ... }
}
Tip/Techni
本周实践了一种设计模式"装饰器"模式,装饰器模式通常为了在不改变原有类的基础上增加新的功能(增加新的装饰器类),此装饰类主要有三个重点:
- 装饰类和原有类实现同一个接口
- 装饰类持有一个原有类的对象,在实现方法中调用原有类的方法
- 客户端生成一个装饰类对象,调用原接口方法实现新的功能
Share
原文在这里Don’t learn a programming language, solve a problem instead
从文章标题就可以看出文章大意:不要只学习编程语言,而要学习解决问题。对这篇文章感兴趣的同学可以去读一下原文,个人工作几年之后的感受就是编程语言只是你诸多技能中很小的一个技能,而解决问题的能力才是一个人最重要的能力,也是很考验一个人各方面的综合能力。
技术再好如果无法用来解决实际问题的话也谈不上真的技术好,而且在平时工作中,领导、公司只会看到你解决了哪些问题,为公司做了什么事情,而不会来在意你用了什么技术。
总结:技术是为解决问题服务的,编程语言只是技术中的一部分。在解决问题的过程中积累技术,在积累技术的过程中更好地解决问题。
欢迎有想法的同学一起交流学习^_^