当前位置: 首页 > news >正文

精选算法合集

一、BFS相关

1.1 最小步骤

给定一个数组,从第一个开始,正好走到数组最后,所使用的最少步骤数。要求:

第一步从第一元素开始,第一步小于<len/2(len为数组的长度)。从第二步开始,只能以所在成员的数字走相应的步数,不能多也不能少, 如果目标不可达返回-1,输出最少的步骤数,不能往回走。

输入7 5 9 4 2 6 8 3 5 4 3 9输出2

输入1 2 3 7 1 5 9 3 2 1输出-1

package JDYL;import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;public class MiniSteps {public int getMiniStep(int[] arr) {int length = arr.length;if (length <= 1) {return 0;}int minStep = Integer.MAX_VALUE;Queue<int[]> queue = new LinkedList<>();boolean[] visited = new boolean[length];for (int i = 1; i < visited.length/2; i++) {visited[i] = true;queue.add(new int[]{i, 1});}visited[0] = true;while (!queue.isEmpty()) {int[] poll = queue.poll();int index = poll[0];int step = poll[1];if (index + arr[index] == length-1) {if (step+1 < minStep) {minStep = step+1;}}if (index + arr[index] < length && !visited[index+arr[index]]) {queue.add(new int[]{index+arr[index], step+1});visited[index + arr[index]] = true;}}if (minStep == Integer.MAX_VALUE) {return -1;}return minStep;}public static void main(String[] args) {MiniSteps miniSteps = new MiniSteps();// 测试用例1int[] arr1 = {7, 5, 9, 4, 2, 6, 8, 3, 5, 4, 3, 9};System.out.println(miniSteps.getMiniStep(arr1)); // 输出 2// 测试用例2int[] arr2 = {1, 2, 3, 7, 1, 5, 9, 3, 2, 1};System.out.println(miniSteps.getMiniStep(arr2)); // 输出 -1}
}

暴力求解法

package org.example.jxsfhj;public class MinStep {int res = Integer.MAX_VALUE;public int getMiniStep(int[] arr) {if (arr.length == 0) {return -1;}int len = arr.length / 2;for (int i = 0; i < len; i++) {getMini(arr, i, 1);}if (this.res == Integer.MAX_VALUE) {return -1;}int result = res;res = Integer.MAX_VALUE;return result;}public void getMini(int[] arr, int currStep, int step) {if (currStep == arr.length - 1) {if (step < res) {res = step;}} else if (currStep < arr.length-1) {int currElem = arr[currStep];if (currElem == 0) {return;}currStep = currStep + currElem;getMini(arr, currStep, step + 1);}}public static void main(String[] args) {MinStep minStep = new MinStep();int[] arr1 = {7, 5, 9, 4, 2, 6, 8, 3, 5, 4, 3, 9};System.out.println(minStep.getMiniStep(arr1));// 测试用例2int[] arr2 = {1, 2, 3, 7, 1, 5, 9, 3, 2, 1};System.out.println(minStep.getMiniStep(arr2));}
}

1.2 二维矩阵两点间所有的最短路径

package algo.backTrace2;import java.util.*;class Node<T> {Node<T> up;Node<T> down;Node<T> left;Node<T> right;T data;void setUp(Node<T> up) {this.up = up;}void setDown(Node<T> down) {this.down = down;}void setLeft(Node<T> left) {this.left = left;}void setRight(Node<T> right) {this.right = right;}void setData(T data) {this.data = data;}public Node<T> getUp() {return this.up;}public Node<T> getDown() {return this.down;}public Node<T> getLeft() {return this.left;}public Node<T> getRight() {return this.right;}public T getData() {return this.data;}@Overridepublic String toString() {return " " + this.getData();}public Node<Integer>[][] getLinkeds(int n) {Node<Integer>[][] nodeArr = new Node[n][n];int m = 1;// 构造node二位数组for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {Node<Integer> node = new Node<>();node.data = m;nodeArr[i][j] = node;m++;}}// 建立指针for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {Node<Integer> current = nodeArr[i][j];// leftif (j - 1 >= 0) {Node<Integer> left = nodeArr[i][j - 1];current.left = left;}// rightif (j + 1 < n) {Node<Integer> right = nodeArr[i][j + 1];current.right = right;}// upif (i - 1 >= 0) {Node<Integer> up = nodeArr[i - 1][j];current.up = up;}// downif (i + 1 < n) {Node<Integer> down = nodeArr[i + 1][j];current.down = down;}}}return nodeArr;}public int allShortestPaths(Node<Integer> start, Node<Integer> target) {if (start == target) {System.out.println("start and targe are the same.");return -1;}// 定义变量Queue<Node<Integer>> queue = new LinkedList<>();Set<Node<Integer>> visited = new HashSet<>();Map<Node<Integer>, Integer> distance = new HashMap<>();Map<Node<Integer>, List<Node<Integer>>> parents = new HashMap<>();// 初始化变量queue.add(start);visited.add(start);distance.put(start, 0);parents.put(start, new ArrayList<>());// 逻辑处理while (!queue.isEmpty()) {Node<Integer> currNode = queue.poll();Node<Integer>[] direct = new Node[]{currNode.getUp(), currNode.getDown(), currNode.getLeft(), currNode.getRight()};for (int i = 0; i < direct.length; i++) {if (direct[i] != null) {int newDistance = distance.get(currNode) + 1;if (!visited.contains(direct[i])) {queue.add(direct[i]);visited.add(direct[i]);distance.put(direct[i], newDistance);parents.put(direct[i], new ArrayList<>());parents.get(direct[i]).add(currNode);} else {if (distance.get(direct[i]) == newDistance) {parents.get(direct[i]).add(currNode);}}}}}if (!visited.contains(target)) {System.out.println("Can not find the target.");return -2;}// 打印输出测试数据// System.out.println("parents : " + parents);//打印路径List<List<Node<Integer>>> results = new ArrayList<>();List<Node<Integer>> currList = new ArrayList<>();currList.add(target);this.printTraces(parents, target, currList, results);System.out.println("所有最短路径");for (List<Node<Integer>> result : results) {for (int i = result.size()-1; i >= 0; i--) {System.out.print(result.get(i) + " ");}System.out.println();}return 1;}public void printTraces(Map<Node<Integer>, List<Node<Integer>>> parents, Node<Integer> currNode, List<Node<Integer>> currList, List<List<Node<Integer>>> results) {List<Node<Integer>> nodes = parents.get(currNode);if (nodes.isEmpty()) {results.add(new ArrayList<>(currList));return;}for (Node<Integer> node : nodes) {currList.add(node);printTraces(parents, node, currList, results);currList.remove(currList.size()-1);}}public void getAllShortestPaths(Node<Integer> start, Node<Integer> target) {this.allShortestPaths(start, target);}
}public class GetAllShortestPaths {public void main(String[] args) {int num = 4;Node<Integer> node = new Node<>();Node<Integer>[][] linkeds = node.getLinkeds(num);System.out.println("生成的二维矩阵:");for (int i = 0; i < num; i++) {for (int j = 0; j < num; j++) {System.out.print(linkeds[i][j].data + " ");}System.out.println();}node.getAllShortestPaths(linkeds[0][0], linkeds[3][3]);}
}

1.3 BFS+回溯

贪吃蛇

现在有一个N*M(N,M=100)的方形矩形,在这个矩形的每一个方格上都放有一个随机值,一条可爱的小蛇从矩形的 左上角开始出发,每次移动都只能移动一格,向右或向下,而每到达一格贪吃的小蛇都会吧该位置上的值吃个一干二净,直到到达右下角时停止。而贪吃的小蛇不怕撑死,它只想吃到最多,并输出路径。

package JDYL;import java.util.*;/*** 带权有向图*/
public class Snake {static class Grap {Map<Integer, List<Edge>> grap;Grap() {grap = new HashMap<>();}public void addEdge(int from, Edge edge) {List<Edge> orDefault = this.grap.getOrDefault(from, new ArrayList<>());orDefault.add(edge);this.grap.put(from, orDefault);}public List<Edge> getAllEdgesByNode(int node) {return grap.get(node);}}static class Edge {int des;int weight;Edge(int des, int weight) {this.des = des;this.weight = weight;}@Overridepublic String toString() {return this.des + "=" + this.weight;}}public void findMaxWeightSum(Grap grap, int start, int target) {Map<Integer, List<Integer>> prev = new HashMap<>();Map<Integer, Integer> disFromStart = new HashMap<>();PriorityQueue<int[]> queue = new PriorityQueue<>(Comparator.comparing(a -> -a[1]));Map<Integer, Boolean> visited = new HashMap<>();grap.grap.forEach((k, edges) -> {visited.put(k, false);});// 初始化visited.put(start, true);queue.offer(new int[]{start, 0});disFromStart.put(start, 0);// BFSwhile (!queue.isEmpty()) {int[] poll = queue.poll();int currNode = poll[0];int currDisFromStart = poll[1];List<Edge> allEdgesByNode = grap.getAllEdgesByNode(currNode);for (Edge edge : allEdgesByNode) {int nextDes = edge.des;int weight = edge.weight;if (nextDes != -1) {int newDisFromStart = currDisFromStart + weight;if (!visited.get(nextDes)) {queue.offer(new int[]{nextDes, newDisFromStart});visited.put(nextDes, true);disFromStart.put(nextDes, currDisFromStart + weight);List<Integer> orDefault = prev.getOrDefault(nextDes, new ArrayList<>());orDefault.add(currNode);prev.put(nextDes, orDefault);} else {if (disFromStart.getOrDefault(nextDes, 0) < newDisFromStart) {disFromStart.put(nextDes, newDisFromStart);List<Integer> list = prev.get(nextDes);list.clear();list.add(currNode);prev.put(nextDes, list);} else if (disFromStart.getOrDefault(nextDes, 0) == newDisFromStart) {List<Integer> list = prev.get(nextDes);list.add(currNode);prev.put(nextDes, list);}}}}}System.out.println("当前节点到开始节点的距离:" + disFromStart);System.out.println("前序节点:" + prev);if (!prev.keySet().contains(target)) {System.out.println("未找到路径");} else {List<List<Integer>> res = new ArrayList<>();this.printTrace(prev, start, target, new ArrayList<>(), res);System.out.println(res);}}public void printTrace(Map<Integer, List<Integer>> prev, int start, int target, List<Integer> currList, List<List<Integer>> result) {currList.add(target);List<Integer> list = prev.get(target);if (target == start) {System.out.println(currList);result.add(new ArrayList<>(currList));return;}for (Integer p : list) {printTrace(prev, start, p, currList, result);currList.remove(currList.size()-1);}}public static void main(String[] args) {Grap grap = new Grap();grap.addEdge(0, new Edge(1, 4));grap.addEdge(0, new Edge(2, 1));grap.addEdge(1, new Edge(3, 2));grap.addEdge(2, new Edge(3, 4));grap.addEdge(2, new Edge(4, 3));grap.addEdge(3, new Edge(5, 1));grap.addEdge(4, new Edge(5, 3));grap.addEdge(5, new Edge(-1, 0));grap.grap.forEach((k, v) -> {System.out.println(k + "=>" + v);});Snake snake = new Snake();snake.findMaxWeightSum(grap, 0, 5);}}

二、回溯算法

2.1 能量消耗

给出一批用户,每个用户有3种选择A\B\C,但是价值不同,相临的用户不能选同一个,求出所有用户选择后总价值最大。

3个用户

30 8 4

50 20 9

11 7 6

输出65,因为选8 50 7

package JDYL;import java.util.ArrayList;
import java.util.List;public class BackTrace3 {Integer value = 0;List<Integer> trace = new ArrayList<>();public void router(int[][] arr) {core(arr, 0, 0, 0, new ArrayList<>());}public void core(int[][] arr, int row, int column, int currValue, List<Integer> currTrace) {if (row == arr.length) {if (currValue>this.value) {this.value = currValue;trace.clear();trace.addAll(currTrace);}return;}for (int currColum = 0; currColum < arr.length; currColum++) {if (currColum == column) {continue;}currTrace.add(arr[row][currColum]);core(arr, row+1, currColum, currValue+arr[row][currColum], currTrace);currTrace.remove(currTrace.size()-1);}}public static void main(String[] args) {int[][] arr = {{30, 8, 4},{50, 20, 9},{11, 7, 6}};BackTrace3 trace3 = new BackTrace3();trace3.router(arr);System.out.println(trace3.value);System.out.println(trace3.trace);}
}

2.2 全排列

package algo.backtrace;import java.util.ArrayList;
import java.util.List;public class HSQanpailie {public List<List<Integer>> router(int[] arr) {List<List<Integer>> results = new ArrayList<>();List<Integer> current = new ArrayList<>();Boolean[] used = new Boolean[arr.length];for (int i = 0; i < used.length; i++) {used[i] = false;}this.qpl(arr, current, used, results);return results;}public void qpl(int[] arr, List<Integer> current, Boolean[] used, List<List<Integer>> results) {if (current.size() == arr.length) {results.add(new ArrayList<>(current));return;}for (int i = 0; i < arr.length; i++) {if (used[i]) {continue;}used[i] = true;current.add(arr[i]);qpl(arr, current, used, results);used[i] = false;current.remove(current.size()-1);}}public void main(String[] args) {int[] arr = {1,2,3};List<List<Integer>> router = this.router(arr);for (List<Integer> list : router) {System.out.println(list);}}
}

2.3 八皇后

package algo.backtrace;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;/*** 8*8矩阵,每一行放置一个皇后,要求满足如下条件:* 相邻两行的皇后不能在上下左右及对角线的位置。*/
public class NQueen {public List<int[][]> slove8QueenRouter(int num) {List<int[][]> results = new ArrayList<>();int[][] current = new int[num][num];for (int i = 0; i < num; i++) {for (int j = 0; j < num; j++) {current[i][j] = 0;}}this.slove8QueenCore(num, 0, current, results);return results;}public boolean isSafe(int[][] current, int row, int column, int num) {int left = 0;for (int i = row; i > 0 ; i--) {left++;// 左上对角线if (column-left>=0 && current[i-1][column-left] == 1) {return false;}// 上列if (current[i-1][column] == 1) {return false;}// 右对角线if (column+left<num && current[i-1][column+left] == 1) {return false;}}return true;}public int[][] copyArray(int[][] arr, int num) {int[][] result = new int[num][num];for (int i = 0; i < num ; i++) {for (int j = 0; j < num; j++) {result[i][j] = arr[i][j];}}return result;}public void slove8QueenCore(int num, int row, int[][] current, List<int[][]> results) {if (row == num) {results.add(copyArray(current, num));return;}for (int cloum = 0; cloum < num; cloum++) {if (isSafe(current, row, cloum, num)) {current[row][cloum] = 1;slove8QueenCore(num, row+1, current, results);current[row][cloum] = 0;}}}public void main(String[] args) {int num = 8;List<int[][]> results = this.slove8QueenRouter(num);System.out.println("results : ");for (int[][] result : results) {for (int i = 0; i < num; i++) {System.out.println(Arrays.toString(result[i]));}System.out.println();}}
}

2.4 Dijkstra 带权图最短路径 (有难度)

package algo.backtrace.Dijkstra.weiwei;import java.util.*;public class Dijkstra {class Grap {// 带权重的无向图表示,邻接矩阵表示Map<Integer, List<Edag>> adjList;Grap() {adjList = new HashMap<>();}// 添加边public void addEdag(int start, int des, int weight) {adjList.putIfAbsent(start, new ArrayList<>());adjList.putIfAbsent(des, new ArrayList<>());adjList.get(start).add(new Edag(des, weight));adjList.get(des).add(new Edag(start, weight));}// 获取一个顶点的所有边public List<Edag> getEdags(int node) {return adjList.getOrDefault(node, new ArrayList<>());}// 获取所有顶点public Set<Integer> getAllNodes() {return adjList.keySet();}}// 描述边class Edag{int des;int weight;Edag(int des, int weight) {this.des = des;this.weight = weight;}}public Map<Integer, Integer> dijkstra(Grap grap, Integer start) {// 定义工具PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparing(a -> a[1]));Map<Integer, Integer> dist = new HashMap<>();Map<Integer, Integer> prev = new HashMap<>();// 初始化参数for (Integer node : grap.getAllNodes()) {dist.put(node, Integer.MAX_VALUE);prev.put(node, -1);}dist.put(start, 0);pq.offer(new int[]{start, 0});while (!pq.isEmpty()) {int[] poll = pq.poll();int currNode = poll[0];int currWeight = poll[1];if (currWeight > dist.get(currNode)) {continue;}for (Edag edag : grap.getEdags(currNode)) {int newDist = currWeight + edag.weight;if (newDist < dist.get(edag.des)) {dist.put(edag.des, newDist);prev.put(edag.des, currNode);pq.offer(new int[]{edag.des, newDist});}}}System.out.println("dist:" + dist);System.out.println("prev:" + prev);return prev;}public void printTrace(Map<Integer, Integer> prevMap, int traget, List<Integer> trace) {if (prevMap.get(traget) == -1) {return;}traget = prevMap.get(traget);printTrace(prevMap, traget, trace);trace.add(traget);}public void main(String[] args) {Grap grap = new Grap();grap.addEdag(0,1,4);grap.addEdag(0,2,1);grap.addEdag(1,3,2);grap.addEdag(2,3,8);grap.addEdag(2,4,3);grap.addEdag(4,5,2);grap.addEdag(3,5,1);Dijkstra dijkstra = new Dijkstra();Map<Integer, Integer> prevMap = dijkstra.dijkstra(grap, 0);List<Integer> list = new ArrayList<>();dijkstra.printTrace(prevMap, 5, list);System.out.println(list);}
}

2.5 动态规划

固定的容积,可以最多装多少?

例如:[5 3 4 6 1 2 9],容积是15,输出为:5,说明是 3 4 1 2

package JDYL;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;public class MaxWeight {int weight = Integer.MIN_VALUE;public List<Integer> router(int[] arr, int max) {List<Integer> result = new ArrayList<>();this.exec(arr, 0, 0, max, new ArrayList<>(), result);return result;}public void exec(int[] arr, int n, int currWeight, int max, List<Integer> currList, List<Integer> result) {if (currWeight>max || n >= arr.length) {return;}if (currWeight>this.weight) {this.weight = currWeight;result.clear();result.addAll(currList);}// 放进去currList.add(arr[n]);currWeight = currWeight+arr[n];n = n+1;exec(arr, n, currWeight, max, currList, result);n = n-1;currWeight = currWeight-arr[n];currList.remove(currList.size()-1);// 不放进去n = n+1;exec(arr, n, currWeight, max, currList, result);n = n-1;}public static void main(String[] args) {int max = 15;String s = "5 3 4 6 1 2 9";String[] split = s.split(" ");int[] arr = Arrays.stream(split).mapToInt(Integer::parseInt).toArray();MaxWeight maxWeight = new MaxWeight();List<Integer> router = maxWeight.router(arr, max);System.out.println(router);System.out.println(maxWeight.weight);}
}//[5, 3, 4, 1, 2]
//        15

三、字符串匹配

3.1 BF

package algo.stringMatch;import java.util.Arrays;
import java.util.Objects;public class BF {public int BF(String mainStr, String subStr) {String[] mainStrArr = mainStr.split("");String[] subStrArr = subStr.split("");for (int i = 0; i < mainStrArr.length - subStrArr.length; i++) {boolean flag = true;for (int j = 0; j < subStrArr.length; j++) {if (!subStrArr[j].equals(mainStrArr[j+i])) {flag = false;}}if (flag) {return i;}}return -1;}public static void main(String[] args) {String mainStr = "wejfhwohfjfdshfdskjhfs";String subStr = "dskj";BF bf = new BF();int index = bf.BF(mainStr, subStr);System.out.println(index);}}

3.2 KMP

package algo.stringMatch;import java.util.Arrays;public class KMPAlgorithm {// 构建部分匹配表public static int[] computeLPSArray(String pat) {int M = pat.length();int[] lps = new int[M];int len = 0;lps[0] = 0; // lps[0] is always 0int i = 1;while (i < M) {if (pat.charAt(i) == pat.charAt(len)) {len++;lps[i] = len;i++;} else {if (len != 0) {len = lps[len - 1];} else {lps[i] = 0;i++;}}}return lps;}// KMP 字符串搜索public static void KMPSearch(String pat, String txt) {int N = txt.length();int M = pat.length();// 创建 lps 数组int[] lps = computeLPSArray(pat);int i = 0; // txt 的索引int j = 0; // pat 的索引while (i < N) {if (pat.charAt(j) == txt.charAt(i)) {i++;j++;}if (j == M) {j = lps[j - 1];}// 未匹配的情况if (i < N && pat.charAt(j) != txt.charAt(i)) {if (j != 0) {j = lps[j - 1];} else {i = i + 1;}}}}public static void main(String[] args) {String txt = "ABABDABACDABABCABAB";String pat = "ABAC";KMPSearch(pat, txt);}
}

四、递归

4.1 获取所有台阶走法

package JDYL;public class GetTotleSteps {int res = 0;public void getPath(int n) {core(n, 0);}public void core(int n, int currIndex) {if (currIndex == n) {res++;return;}if (currIndex < n) {// 走1个台阶core(n, currIndex+1);// 走2个台阶core(n, currIndex+2);}}public static void main(String[] args) {int n = 2;GetTotleSteps getTotleSteps = new GetTotleSteps();getTotleSteps.getPath(n);System.out.println(getTotleSteps.res);}
}

4.2 兔子繁殖

3个月兔子长大,然后每个月都会生产一只小兔,问N天后,一共有多少只小兔。

package JDYL;public class RabbitsCount {public int getRabbits(int days) {int months = (days + 29) / 30;int[] rabbits = new int[months+1];rabbits[1] = 1;rabbits[2] = 1;rabbits[3] = 1;for (int i = 4; i < months+1; i++) {rabbits[months] = rabbits[months-1]+rabbits[months-3];}return rabbits[months];}public static void main(String[] args) {int n = 70;RabbitsCount rabbitsCount = new RabbitsCount();int rabbits = rabbitsCount.getRabbits(n);System.out.println(rabbits);}
}

五、边界处理

5.1 喊7的次数重排

喊7是一个传统的聚会游戏,N个人围成一圈,按顺时针从1到N编号。编号为1的人从1开始喊数,下一个人喊的数字为上一个人的数字加1,但是当数字是7的倍数或者数字本身含有7的话,要喊"过"。现给定一个长度为N的数组,存储了打乱顺序的每个人喊"过"的次数,请把它还原成正确的顺序,即数组的第i个元素存储编号i的人喊"过"的次数。

输入为一行,为空格分隔的喊"过"的次数,

示例1

输入

0 1 0

输出

1 0 0

说明

一共只有一次喊"过",那只会发生在需要喊7时,按顺序,编号为1的人会遇到7,故输出1 0 0。注意,结束时的K不一定是7,也可以是8、9等,喊过的次数都是1 0 0。

示例2

输入

0 0 0 2 1

输出

0 2 0 1 0

说明

一共有三次喊"过",发生在7 14 17,按顺序,编号为2的人会遇到7 17,编号为4的人会遇到14,故输出0 2 0 1 0。

package JDYL;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;public class ContionsSevle {public boolean isContions7(int n) {return n%7 == 0 || String.valueOf(n).contains("7");}public int[] exec(int[] arr) {int[] res = new int[arr.length];// 一共几个人int people = arr.length;// 一共叫过几次int sum = 0;for (int i = 0; i < arr.length; i++) {sum += arr[i];}int tmpCount = 0;int n = 1;while (tmpCount < sum) {if (isContions7(n)) {res[n%people-1]++;tmpCount++;}n++;}return res;}public static void main(String[] args) {int[] arr = {0,0,0,2,1};ContionsSevle contionsSevle = new ContionsSevle();int[] exec = contionsSevle.exec(arr);System.out.println(Arrays.toString(exec));}
}

六、循环数组

循环数组解题技巧:

  1. i%n 来模拟循环。
  2. 循环2次,来比较最后一个元素和第一个元素。
  3. 借助栈来解题,与当前元素距离最近,其实栈弹出后是个倒序。

例题:

找出比自己大的数

给一个数组,收尾相连,按照顺序找到比自己大的第一个数,找不到的存-1。

例如[35,25,48,37] ->输出[48,48,-1,48]

package JDYL;import java.util.Stack;public class NextGreaterElement {public static int[] nextGreaterElements(int[] nums) {int n = nums.length;int[] result = new int[n];Stack<Integer> stack = new Stack<>();// 初始化结果数组,默认值为 -1for (int i = 0; i < n; i++) {result[i] = -1;}// 遍历数组两遍,模拟循环for (int i = 0; i < 2 * n; i++) {int currentIndex = i % n;  // 取模操作,模拟循环// 如果栈不为空且当前元素大于栈顶元素,则找到下一个比栈顶元素大的数while (!stack.isEmpty() && nums[stack.peek()] < nums[currentIndex]) {int idx = stack.pop();result[idx] = nums[currentIndex];}// 仅将元素索引压入栈if (i < n) {  // 只在第一次遍历时压入索引stack.push(currentIndex);}}return result;}public static void main(String[] args) {int[] nums = {35, 25, 48, 37};int[] result = nextGreaterElements(nums);// 输出结果for (int num : result) {System.out.print(num + " ");}}
}

七、排序算法

思想设计的巧妙和边界问题尤为需要注意的当属归并排序和快速排序两个排序算法,且对应的算法时间复杂度都是O(nlogn),相比冒泡,插入等排序算法的O(N^2)复杂度要低,更加常用。

要重点体会“思想的巧妙”和“边界的处理”。

7.1 归并排序

package org.example.JDAL;import java.util.Arrays;public class MergeSort {// 测试归并排序public static void main(String[] args) {int[] arr = {12, 11, 13, 5, 6, 7};System.out.println("排序前数组:" + Arrays.toString(arr));MergeSort mergeSort = new MergeSort();mergeSort.mergeSort(arr);System.out.println("排序后数组:" + Arrays.toString(arr));}private void mergeSort(int[] arr) {int length = arr.length;if (length <= 1) {return;}int mid = length/2;int[] left = new int[mid];int[] right = new int[length-mid];for (int i = 0; i < mid; i++) {left[i] = arr[i];}for (int i = mid; i < length; i++) {right[i-mid] = arr[i];}this.mergeSort(left);this.mergeSort(right);this.merge(arr, left, right);}private void merge(int[] arr, int[] left, int[] right) {int i=0;int j=0;int k=0;while (i<left.length && j < right.length) {if (left[i] <= right[j]) {arr[k] = left[i];i++;} else {arr[k] = right[j];j++;}k++;}if (i<left.length) {for (int l = i; l < left.length; l++) {arr[k] = left[l];k++;}}if (j<right.length) {for (int l = j; l < right.length; l++) {arr[k] = right[l];k++;}}}
}

7.2 快速排序

package org.example.JDAL;import java.util.Arrays;public class QuickSortTest {public void quickSort(int[] arr, int s, int e) {if (s>=e) {return;}int p = partition(arr,s,e);this.quickSort(arr, s, p-1);this.quickSort(arr, p+1, e);}public int partition(int[] arr, int s, int e) {int p = arr[e];int m=s;for (int i = s; i < e; i++) {if (arr[i] <= p) {int tmp = arr[i];arr[i] = arr[m];arr[m] = tmp;m++;}}int tmp = arr[e];arr[e] = arr[m];arr[m] = tmp;return m;}public static void main(String[] args) {int[] arr = {7,5,1,2,3,4,8,9};QuickSortTest quickSortTest = new QuickSortTest();quickSortTest.quickSort(arr, 0, arr.length-1);System.out.println(Arrays.toString(arr));}
}

八、双指针

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

package JDYL;import java.util.Arrays;class RemoveDuplicates2 {public static void main(String[] args) {int[] nums = {1, 1, 1, 2,2,2, 2, 3};int newLength = removeDuplicates(nums);// 输出新数组的长度和修改后的数组System.out.println("New length: " + newLength);for (int i = 0; i < newLength; i++) {System.out.print(nums[i] + " ");}}public static int removeDuplicates(int[] nums) {if (nums == null || nums.length == 0) {return 0;}int slow = 1;  // slow 指针从第二个元素开始int count = 1; // count 用于记录当前元素出现的次数// 遍历数组,从第二个元素开始for (int fast = 1; fast < nums.length; fast++) {if (nums[fast] == nums[fast - 1]) {count++;} else {count = 1; // 如果遇到不同的元素,重置 count}// 如果 count <= 2,说明当前元素可以保留if (count <= 2) {nums[slow] = nums[fast];slow++;}}System.out.println(Arrays.toString(nums));return slow; // slow 即为新数组的长度}
}

九、数组操作(TODO)

  1. 获取指定数组的子数组
  2. 合并两个子数组为一个大数组

十、字符串操作(TODO)

  1. 获取指定字符串的子串
  2. 合并多个字符串

十一、跳跃游戏(贪心思想)

给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。

示例 1:

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

示例 2:

输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
package org.example.JDAL;public class JumpGame {public static void main(String[] args) {int[] nums = {3, 2, 1, 0, 4};boolean b = jumpCore(nums);System.out.println(b);}private static boolean jumpCore(int[] nums) {int maxLen = 0;for (int i = 0; i < nums.length; i++) {if (i>maxLen) {return false;}maxLen = Math.max(i+nums[i], maxLen);}return true;}
}

十二、跳跃游戏2(贪心思想)

给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]

每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:

  • 0 <= j <= nums[i] 
  • i + j < n

返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]

示例 1:

输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。

示例 2:

输入: nums = [2,3,0,1,4]
输出: 2

提示:

  • 1 <= nums.length <= 104
  • 0 <= nums[i] <= 1000
  • 题目保证可以到达 nums[n-1]
package org.example.JDAL;public class MinSteps2 {public static int jump(int[] nums) {int n = nums.length;int end = 0;int maxPosition = 0;int steps = 0;for (int i = 0; i < n - 1; i++) {// 计算能到达的最远距离maxPosition = Math.max(maxPosition, i + nums[i]);if (i == end) {end = maxPosition;steps++;}}return steps;}public static void main(String[] args) {int[] nums1 = {2, 3, 1, 1, 4};int[] nums2 = {2, 3, 0, 1, 4};System.out.println(jump(nums1));System.out.println(jump(nums2));}
}00片;【

十三、数据结构与算法复杂度

O(1) 时间插入、删除和获取随机元素

实现RandomizedSet 类:

  • RandomizedSet() 初始化 RandomizedSet 对象
  • bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false 。
  • bool remove(int val) 当元素 val 存在时,从集合中移除该项,并返回 true ;否则,返回 false 。
  • int getRandom() 随机返回现有集合中的一项(测试用例保证调用此方法时集合中至少存在一个元素)。每个元素应该有 相同的概率 被返回。

你必须实现类的所有函数,并满足每个函数的 平均 时间复杂度为 O(1) 。

示例:

输入
["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
[[], [1], [2], [2], [], [1], [2], []]
输出
[null, true, false, true, 2, true, false, 2]解释
RandomizedSet randomizedSet = new RandomizedSet();
randomizedSet.insert(1); // 向集合中插入 1 。返回 true 表示 1 被成功地插入。
randomizedSet.remove(2); // 返回 false ,表示集合中不存在 2 。
randomizedSet.insert(2); // 向集合中插入 2 。返回 true 。集合现在包含 [1,2] 。
randomizedSet.getRandom(); // getRandom 应随机返回 1 或 2 。
randomizedSet.remove(1); // 从集合中移除 1 ,返回 true 。集合现在包含 [2] 。
randomizedSet.insert(2); // 2 已在集合中,所以返回 false 。
randomizedSet.getRandom(); // 由于 2 是集合中唯一的数字,getRandom 总是返回 2 。
package org.example.JDAL;import java.util.*;// O(1) 时间插入、删除和获取随机元素
public class RandomizedSet {Map<Integer, Integer> map;List<Integer> list;Random random;public RandomizedSet() {// 查询 O(1)的有:Array | HashMap// 插入 list | hashMap// 删除 list | hashMapmap = new HashMap<>();list = new ArrayList<>();random = new Random();}public boolean insert(int val) {if (this.map.containsKey(val)) {return false;}// insertthis.list.add(val);int size = this.list.size();this.map.put(val, size);return true;}public boolean remove(int val) {if (!this.map.containsKey(val)) {return false;}// removeInteger index = this.map.get(val);int last = list.get(list.size()-1);list.set(index, last);map.put(last, index);list.remove(list.size()-1);map.remove(val);return true;}public int getRandom() {int i = this.random.nextInt(this.list.size());return this.map.get(i);}public static void main(String[] args) {}}

十三、正向思维与逆向思维

给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在  32 位 整数范围内。

请 不要使用除法,且在 O(n) 时间复杂度内完成此题。

示例 1:

输入: nums = [1,2,3,4]
输出: [24,12,8,6]

示例 2:

输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]

提示:

  • 2 <= nums.length <= 105
  • -30 <= nums[i] <= 30
  • 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在  32 位 整数范围内

进阶:你可以在 O(1) 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组 不被视为 额外空间。)

package org.example.JDAL;import java.util.Arrays;public class ProductExceptSelf2 {public static void main(String[] args) {int[] nums = {1,2,3,4};ProductExceptSelf2 exceptSelf2 = new ProductExceptSelf2();int[] res = exceptSelf2.route(nums);System.out.println(Arrays.toString(res));}private int[] route(int[] nums) {int length = nums.length;int[] L = new int[length];int[] R = new int[length];int[] res = new int[length];L[0] = 1;for (int i = 1; i < nums.length; i++) {L[i] = L[i-1]*nums[i-1];}R[length-1] = 1;for (int i = length-2; i >= 0; i--) {R[i] = R[i+1]*nums[i+1];}for (int i = 0; i < res.length; i++) {res[i] = L[i]*R[i];}System.out.println(Arrays.toString(L));System.out.println(Arrays.toString(R));return res;}}

十四、YangQG 面试题汇总

YangQG 面试题汇总-CSDN博客

14.1 交叉链表

解题思想:

双指针思想

package org.example.YangQianGuan;class Node {int data;Node next;Node(int val) {this.data = val;this.next = null;}@Overridepublic String toString() {return " {data: " + this.data + " next: " + this.next + "} ";}
}public class IntersectionNode {public Node getStartInter(Node headA, Node headB) {if (headA == null || headB == null) {return null;}Node pA = headA;Node pB = headB;while (pA!= pB) {pA = pA == null? headB : pA.next;pB = pB == null? headA : pB.next;}return pA;}public static void main(String[] args) {// node listNode node8 = new Node(8);Node node4 = new Node(4);Node node5 = new Node(5);node8.next = node4;node4.next = node5;// A listNode headA = new Node(4);Node nodeA1 = new Node(1);headA.next = nodeA1;nodeA1.next = node8;// B ListNode headB = new Node(5);Node nodeB1 = new Node(6);Node nodeB2 = new Node(1);headB.next = nodeB1;nodeB1.next = nodeB2;nodeB2.next = node8;IntersectionNode intersectionNode = new IntersectionNode();Node startInter = intersectionNode.getStartInter(headA, headB);System.out.println(startInter);}
}

十五、背包问题

背包问题是经典的算法问题,其变种多背包算法在实际项目中也有应用,这次让我们一起来搞懂背包算法。

背包

0-1背包

package org.example;import java.util.ArrayList;
import java.util.List;public class Knapsack {int maxW = 0;public static void main(String[] args) {int[] weight = {1, 2, 3, 4, 5, 6, 7, 8, 9};
//        int max = 31; // 91int max = 91; // 91Knapsack knapsack = new Knapsack();List<Integer> res = knapsack.getMaxW(weight, max);System.out.println("maxW :" + knapsack.maxW + " res : " + res);}private List<Integer> getMaxW(int[] weight, int max) {List<Integer> res = new ArrayList<>();int currIdx = 0;int currW = 0;List<Integer> currList = new ArrayList<>();this.exec(weight, max, currIdx, currW, currList, res);return res;}private void exec(int[] weight, int max, int currIdx, int currW, List<Integer> currList, List<Integer> res) {if (currW == max || currIdx == weight.length) {if (currW > this.maxW) {this.maxW = currW;res.clear();res.addAll(currList);}return;}// 当前物品放进背包if (currW + weight[currIdx] <= max) {currW += weight[currIdx];currList.add(weight[currIdx]);this.exec(weight, max, currIdx + 1, currW, currList, res);currList.remove(currList.size() - 1);currW -= weight[currIdx];}// 当前物品不放进背包this.exec(weight, max, currIdx + 1, currW, currList, res);}}

多背包

相关文章:

精选算法合集

一、BFS相关 1.1 最小步骤 给定一个数组&#xff0c;从第一个开始&#xff0c;正好走到数组最后&#xff0c;所使用的最少步骤数。要求&#xff1a; 第一步从第一元素开始&#xff0c;第一步小于<len/2&#xff08;len为数组的长度&#xff09;。从第二步开始&#xff0c…...

HackMyVM-Klim靶机的测试报告

目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、信息搜集 2、Getshell 3、提权 CVE-2008-0166 四、结论 一、测试环境 1、系统环境 渗透机&#xff1a;kali2021.1(192.168.159.127) 靶 机&#xff1a;debian(192.168.159.27) 注意事…...

C++内存分布

小试牛刀&#xff1a; int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] { 1, 2, 3, 4 };char char2[] "abcd";const char* pChar3 "abcd";int* ptr1 (int*)malloc(sizeof(int)…...

mysql主从复制sql进程中断,报错Tablespace is missing for table ……

一 解决办法 关键执行1.2步&#xff0c;1.1/1.3结合实际环境操作。 1.1 如果从库只读开启了&#xff0c;要先关闭只读 show variables like %read_only%; set global super_read_onlyoff; set global read_onlyoff; 1.2 discart/import tablespace ALTER TABLE 表名 DISC…...

STM32 FreeRTOS 信号量

信号量的简介 reeRTOS中的信号量是一种用于任务间同步和资源管理的机制。信号量可以是二进制的&#xff08;只能取0或1&#xff09;也可以是计数型的&#xff08;可以是任意正整数&#xff09;。信号量的基本操作包括“获取”和“释放”。 比如动车上的卫生间&#xff0c;一个…...

Codemirror6个人使用心得总结

Codemirror6 包 用法总结 本次用到的 Codemirror6 有关的包如下 语法支持包语法支持包核心插件codemirror/lang-yaml 6.1.1codemirror/lang-less 6.0.2codemirror/autocomplete 6.16.0codemirror/lang-xml 6.1.0codemirror/lang-liquid 6.2.1codemirror/commands 6.5.0codemirr…...

Ruby语言的软件开发工具

Ruby语言的软件开发工具概述 引言 Ruby是一种高效、灵活的动态编程语言&#xff0c;因其简洁的语法和强大的功能而受到开发者的欢迎。在软件开发过程中&#xff0c;使用合适的开发工具可以大幅提高工作效率&#xff0c;提升代码质量。本文将详细介绍一些常用的Ruby开发工具&a…...

OpenHarmony API 设计规范

OpenHarmony API 设计规范 修订记录 版本作者时间更新内容v0.1&#xff0c;试运行版OpenHarmony API SIG2022年11月初版发布 目的 API是软件实现者提供给使用者在编程界面上的定义&#xff0c;API在很大程度上体现了软件实体的能力范围。 同时&#xff0c;API定义的好坏极…...

ESP8266 AP模式 网页配网 arduino ide

ESP8266的AP配网,可以自行配置网络,一个简单的demo,文档最后有所有的代码,已经测试通过. 查看SPIFFS文件管理系统中的文件 账号密码是否存在,如不存在进入AP配网,如存在进入wifi连接模式 // 检查Wi-Fi凭据if (isWiFiConfigured()) {Serial.println("找到Wi-Fi凭据&#…...

OpenCV基础:获取子矩阵的几种方式

目录 相关阅读 方法一&#xff1a;使用切片操作 方法二&#xff1a;使用高级索引 方法三&#xff1a;使用条件筛选 方法四&#xff1a;使用 numpy 的 take 函数 相关阅读 OpenCV基础&#xff1a;矩阵的创建、检索与赋值-CSDN博客 OpenCV基础&#xff1a;图像运算-CSDN博客…...

C++ 之多线程相关总结

C 之多线程相关总结 1.多线程相关基础知识 1.1 线程的创建和管理 1. std::thread 类&#xff1a; 用于创建和管理线程。通过将可调用对象&#xff08;如函数、函数对象、lambda 表达式&#xff09;作为参数传递给 std::thread 的构造函数&#xff0c;可以创建一个新的线程。…...

EF Core全局查询筛选器

目录 概述 用法 添加全局查询筛选器 禁用全局查询筛选器 概述 全局查询筛选器&#xff1a;EF Core 会自动将这个查询筛选器应用于涉及这个实体类型的所有 LINQ 查询。 场景&#xff1a;软删除、多租户。 什么是软删除&#xff1f; 逻辑删除&#xff0c;并不是真正地从数…...

【开源免费】基于SpringBoot+Vue.JS欢迪迈手机商城(JAVA毕业设计)

本文项目编号 T 141 &#xff0c;文末自助获取源码 \color{red}{T141&#xff0c;文末自助获取源码} T141&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...

Objective-C语言的数据库交互

Objective-C语言的数据库交互 引言 在现代应用程序开发过程中&#xff0c;数据库在数据存储和管理方面起着至关重要的作用。对于iOS应用开发者而言&#xff0c;掌握如何在Objective-C中与数据库交互显得尤为重要。本文将全面探讨Objective-C的数据库交互&#xff0c;包括SQLi…...

基于 Spring Boot 和 Vue.js 的全栈购物平台开发实践

在现代 Web 开发中&#xff0c;前后端分离的架构已经成为主流。本文将分享如何使用 Spring Boot 和 Vue.js构建一个全栈购物平台&#xff0c;涵盖从后端 API 开发到前端页面实现的完整流程。 1. 技术栈介绍 后端技术栈 JDK 1.8&#xff1a;稳定且广泛使用的 Java 版本。 Spring…...

笔记(数据运营方向)

以下是一些在工作过程中的小笔记&#xff0c;写的比较杂乱&#xff0c;后续再进行分类~ 1、掌握sql窗口函数 窗口函数又名开窗函数&#xff0c;属于分析函数的一种。用于解决复杂报表统计需求的功能强大的函数。窗口函数用于计算基于组的某种聚合值&#xff0c;它和聚合函数的…...

qt vs ios开发应用环境搭建和上架商店的记录

qt 下载链接如下 https://download.qt.io/new_archive/qt/5.14/5.14.2/qt-opensource-mac-x64-5.14.2.dmg 安装选项全勾选就行&#xff0c;这里特别说明下qt5.14.2/qml qt5.14.2对qml支持还算成熟&#xff0c;但很多特性还得qt6才行&#xff0c;这里用qt5.14.2主要是考虑到服…...

[cg] glDrawBuffers MRT的应用

glDrawBuffers 是 OpenGL 中的一个函数&#xff0c;用于指定渲染结果输出到哪些颜色缓冲区。它通常在多渲染目标&#xff08;MRT, Multiple Render Targets&#xff09;中使用&#xff0c;允许一个渲染操作同时将结果输出到多个颜色缓冲区&#xff0c;而不是默认情况下的单个颜…...

IO模型与NIO基础二

抽象基类之二 FilterInputStream FilterInputStream 的作用是用来“封装其它的输入流&#xff0c;并为它们提供额外的功能”。 它的常用的子类有BufferedInputStream和DataInputStream。 (1) BufferedInputStream的作用就是为“输入流提供缓冲功能&#xff0c;以及mark()和res…...

【设计模式】 单例模式(单例模式哪几种实现,如何保证线程安全,反射破坏单例模式)

单例模式 作用&#xff1a;单例模式的核心是保证一个类只有一个实例&#xff0c;并且提供一个访问实例的全局访问点。 实现方式优缺点饿汉式线程安全&#xff0c;调用效率高 &#xff0c;但是不能延迟加载懒汉式线程安全&#xff0c;调用效率不高&#xff0c;能延迟加载双重检…...

测试微信模版消息推送

进入“开发接口管理”--“公众平台测试账号”&#xff0c;无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息&#xff1a; 关注测试号&#xff1a;扫二维码关注测试号。 发送模版消息&#xff1a; import requests da…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...