防止重复路径
847
通过状态压缩,记录每次 入节点 的路径
boolean[][] seen = new boolean[n][1 << n];
最短路问题
542
图构建优化
127
通过增加虚拟节点
字典树(前缀树)
class Trie {
boolean q;
String val;
Set<Trie> nexts;
public Trie() {
this.nexts=new HashSet();
}
public void insert(String word) {
Trie trie=this;
boolean has;
while(word.length()>0){
has=false;
for(Trie t:trie.nexts){
if(t.val.equals(word.substring(0,1))){
word=word.substring(1);
trie=t;
has=true;
break;
}
}
if(!has){
break;
}
}
if(word.length()==0){
trie.q=true;
}
Trie t;
while(word.length()>0){
t=new Trie();
t.q=false;
t.val=word.substring(0,1);
word=word.substring(1);
trie.nexts.add(t);
trie=t;
}
trie.q=true;
}
public void print(){
for(Trie t:this.nexts){
System.out.println(t.val+" "+t.q);
print(t);
}
}
public void print(Trie t){
for(Trie trie:t.nexts){
System.out.println(trie.val+" "+trie.q);
print(trie);
}
}
public boolean search(String word) {
Trie trie=this;
boolean has;
while(word.length()>0){
has=false;
for(Trie t:trie.nexts){
if(t.val.equals(word.substring(0,1))){
word=word.substring(1);
trie=t;
has=true;
break;
}
}
if(!has){
return false;
}
}
if(!trie.q){
return false;
}
return true;
}
public boolean startsWith(String prefix) {
Trie trie=this;
boolean has;
while(prefix.length()>0){
has=false;
for(Trie t:trie.nexts){
if(t.val.equals(prefix.substring(0,1))){
prefix=prefix.substring(1);
trie=t;
has=true;
break;
}
}
if(!has){
return false;
}
}
return true;
}
}
单调栈
/**
* 单调栈
* 数组中没有重复值
*
* @param arr
* @return
*/
public static int[][] getNearLessNoRepeat(int[] arr) {
int[][] ret = new int[arr.length][2];
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < arr.length; i++) {
while (!stack.isEmpty() && arr[stack.peek()] > arr[i]) {
//弹栈并记录相关信息
int index = stack.pop();
ret[index][1] = i;//记录右边离index最近且小的元素
ret[index][0] = stack.isEmpty() ? -1 : stack.peek();//记录左边离index最近且小的元素
}
stack.push(i);
}
while (!stack.isEmpty()) {
int index = stack.pop();
ret[index][1] = -1;//没有右边最近且小的元素
ret[index][0] = stack.isEmpty() ? -1 : stack.peek();
}
return ret;
}
/**
* 单调栈
* 数组中有重复值
*
* @param arr
* @return
*/
public static int[][] getNearLess(int[] arr) {
int[][] res = new int[arr.length][2];
Stack<List<Integer>> stack = new Stack<>();
for (int i = 0; i < arr.length; i++) {
while (!stack.isEmpty() && arr[stack.peek().get(0)] > arr[i]) {
List<Integer> list = stack.pop();
//左边最近且小的元素为栈顶集合最后一个索引
Integer left = stack.isEmpty() ? -1 : stack.peek().get(stack.peek().size() - 1);
for (Integer integer : list) {
res[integer][0] = left;
res[integer][1] = i;
}
}
//判断当前栈顶值是否等于待入栈元素的值
if (!stack.isEmpty() && arr[stack.peek().get(0)] == arr[i]) {
stack.peek().add(i);
} else {
ArrayList<Integer> list = new ArrayList<>();
list.add(i);
stack.push(list);
}
}
while (!stack.isEmpty()) {
List<Integer> pop = stack.pop();
Integer left = stack.isEmpty() ? -1 : stack.peek().get(stack.peek().size() - 1);
for (Integer integer : pop) {
res[integer][0] = left;
res[integer][1] = -1;
}
}
return res;
}
前缀和
存在数组nums,长度为n
前缀和就是将数组前 nums[i]=前 i 项和。
如果求连续数组长度的话,配合哈希表最佳。哈希表可存储最先出现nums[i]值的下标。
相关题:力扣525题
并查集
并查集是一种树型的数据结构。它的特点是由子结点找到父亲结点,用于处理一些不交集的合并及查询问题。
Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。
Union:将两个子集合并成同一个集合。
class UnionFind {
int[] parents;
public UnionFind(int totalNodes) {
parents = new int[totalNodes];
for (int i = 0; i < totalNodes; i++) {
parents[i] = i;
}
}
/**
* 合并连通区域是通过find来操作的, 即看这两个节点是不是在一个连通区域内
* @param node1
* @param node2
*/
void union(int node1, int node2) {
int root1 = find(node1);
int root2 = find(node2);
if (root1 != root2) {
parents[root2] = root1;
}
}
int find(int node) {
while (parents[node] != node) {
// 当前节点的父节点 指向父节点的父节点.
// 保证一个连通区域最终的parents只有一个.
parents[node] = parents[parents[node]];
node = parents[node];
}
return node;
}
boolean isConnected(int node1, int node2) {
return find(node1) == find(node2);
}
}