Java當中常用的算法

文章目錄

  • 算法
    • 二叉樹左右變換數據
    • 二分法
      • 實現
    • 冒泡排序算法
    • 插入排序算法
    • 快速排序算法
    • 希爾排序算法
    • 歸并排序算法
    • 桶排序算法
    • 基數排序算法
    • 分治算法
    • 漢諾塔問題
    • 動態規劃算法
        • 引子
        • 代碼實現背包問題
    • KMP算法
      • 什么是KMP算法
      • 暴力匹配
      • KMP算法實現

今天我們來看看常用的算法,開干。。。。。

算法

二叉樹左右變換數據

在這里插入圖片描述

實現的代碼如下:以下定義的類是內部類

//    2. 講一個做二叉樹左右替換
//    1. 先給一個二叉樹的內部類,類里面分出左右的對象的變量public static class Tree {private Object data;public Object getData() {return data;}public void setData(Object data) {this.data = data;}public Tree getLeft() {return left;}public void setLeft(Tree left) {this.left = left;}public Tree getRight() {return right;}public void setRight(Tree right) {this.right = right;}// 給出左右的樹private Tree left;private Tree right;// 構造方法public Tree(Object data, Tree left, Tree right) {this.data = data;this.left = left;this.right = right;}/*** 獲取二叉樹的深度* @param root root* @return int*/public static int getMaxDepth(Tree root) {if (root == null) return 0;// 需要遞歸獲取深度return Math.max(getMaxDepth(root.left), getMaxDepth(root.right)) + 1;}/*** 二叉樹的交換方法OK,經過驗證* @param root Tree*/public static void swap(Tree root) {if (root == null) return;// 交換Tree tmp = root.left;root.left = root.right;root.right = tmp;// 遞歸交換swap(root.left);swap(root.right);}/***  二叉樹的左右交換* @param root*/public static void swapAgin(Tree root) {if (root == null) return;Stack<Tree> statck = new Stack<>();statck.push(root);while (!statck.isEmpty()) {Tree node = statck.pop();Tree tmp = node.left;node.left = node.right;node.right = tmp;if (node.left != null) {statck.push(node.left);}if (node.right != null) {statck.push(node.right);}}}public static void main(String[] args) {// 以下模擬的二叉樹圖片地址在此: https://img-blog.csdnimg.cn/1ae454d94ab04d8e8fb6f313248beb3a.pngTree left9 = new Tree(9, null, null);Tree right3 = new Tree(3, null, null);Tree right8 = new Tree(8, null, null);Tree left7 = new Tree(7, null, right8);Tree right11 = new Tree(11, left9, right3);Tree root5 = new Tree(5, left7, right11);System.out.println("原始的二叉樹結果:" + root5);
//       交換swap(root5);
//            swapAgin(root5);System.out.println("swap()方法交換之后的二叉樹結構為:" + root5);}}

二分法

概念:

  • 二分法(Bisection method) 即一分為二的方法,又叫折半查找方法。
  • 把一組有序數列分為左右兩部分,從這組數字的中間位置開始找:
  • 如果中間位置的數等于目標數,則直接返回;
  • 如果中間位置的數大于目標數,則從左邊部分查找;
  • 如果小于目標數,則從右邊部分查找;
  • 重復以上過程,直到找到滿足條件的記錄,使查找成功。

時間復雜度:
都是 O(log2 N)

空間復雜度:
非遞歸方式: 空間復雜度是O(1);
遞歸方式: 空間復雜度:O(log2N )

實現

1. 遞歸方式

 public static int binarySearchRecursive(int[] arr, int low, int high, int key) {//邊界條件:如果目標數沒有在數組范圍內(即比最左邊的數小,比最右邊的數大)if (arr == null || arr.length == 0 || arr[low] > key || arr[high] < key || low > high) {return -1;}// 獲取中間位置下標int mid = (low + high) / 2;// 將中間位置的數和目標數作比較,如果中間位置的數等于目標數,則直接返回下標,// 如果中間位置的數大于目標數,則將左邊部分用遞歸方法繼續查找;如果小于目標數,則從右邊部分用遞歸方法繼續查找if (arr[mid] == key) {return mid;} else if (arr[mid] > key) {return binarySearch(arr, low, mid - 1, key);} else {return binarySearch(arr, mid + 1, high, key);}}// 測試下:從一組數中找3,輸出數組下標public static void main(String[] args) {int[] arr = {2, 3, 5, 7, 9, 78, 90, 167};System.out.println(binarySearchRecursive(arr, 0, (arr.length) - 1, 3));}

2. 非遞歸方式

 public static int binarySearch(int[] arr, int key) {int low = 0;int high = arr.length - 1;while (low <= high) {int middle = (low + high) / 2;if (key < arr[middle]) {high = middle - 1;} else if (key > arr[middle]) {low = middle + 1;} else {return middle;}}return -1;}// 測試下:從一組數中找3,輸出數組下標public static void main(String[] args) {int[] arr = {2, 3, 5, 7, 9, 78, 90, 167};System.out.println("數組下標:"+binarySearch(arr, 3));}

3.非遞歸

/*** 二分查找* @param srcArray 源數組* @param des 目標元素* @return 如果找到則返回索引位置,找不到則返回-1*/
public static int binarySearch(int[] srcArray, int des) {//定義初始最小、最大索引int start = 0;int end = srcArray.length - 1;//確保不會出現重復查找,越界while (start <= end) {//計算出中間索引值  >>> 邏輯右移 也就是 int middle = (end + start)/2int middle = (end + start)>>>1 ;//防止溢出if (des == srcArray[middle]) {return middle;//判斷下限} else if (des < srcArray[middle]) {end = middle - 1;//判斷上限} else {start = middle + 1;}}//若沒有,則返回-1return -1;
}

冒泡排序算法

算法原理
比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
對每一對相鄰元素做同樣的工作,從開始第一對到結尾的最后一對。在這一點,最后的元素應該會是最大的數。
針對所有的元素重復以上的步驟,除了最后一個。
持續每次對越來越少的元素重復上面的步驟,直到沒有任何一對數字需要比較。

示例代碼:

public static void bubbleSort(int arr[]) {for (int i = 0; i < arr.length - 1; i++) {for (int j = 0; j < arr.length - 1 - i; j++) {if (arr[j] > arr[j + 1]) {int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}

示例代碼2:

public static void bubbleSort2(int[] a, int n) {int i, j;for (i = 0; i < n; i++) {//表示 n 次排序過程。for (j = 1; j < n - i; j++) {if (a[j - 1] > a[j]) {//前面的數字大于后面的數字就交換//交換 a[j-1]和 a[j]int temp;temp = a[j - 1];a[j - 1] = a[j];a[j] = temp;}}}
}

插入排序算法

(1)概念:通過構建有序序列,對于未排序數據,在已排序序列中從后向前掃描,找到相應的位置并插入。

(2)一個通俗的比喻

插入排序就類似于斗地主時,整理撲克牌的情況。第一次摸牌時,左收是空的,之后每次摸牌插入到左手的牌時,都會將這張牌和左手中已經排好序的牌,從右到左比較,確認這張牌該放的位置。

示例代碼:

public static void insertionSort(int arr[]) {for (int i = 1; i < arr.length; i++) {//插入的數int insertVal = arr[i];//被插入的位置(準備和前一個數比較)int index = i - 1;//如果插入的數比被插入的數小while (index >= 0 && insertVal < arr[index]) {//將把 arr[index] 向后移動arr[index + 1] = arr[index];//讓 index 向前移動index--;}//把插入的數放入合適位置arr[index + 1] = insertVal;}
}

快速排序算法

(1)概念:快速排序是指通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然后再按此方法對這兩部分數據分別進行快速排序。整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。

(2)快速排序的的過程簡圖:

選擇一個關鍵值作為基準值。比基準值小的都在左邊序列(一般是無序的),比基準值大的都在右邊(一般是無序的)。

在這里插入圖片描述

示例代碼:

/*** 快速排序** @param arr   需要排序的數組* @param start 數組的最小索引: 0* @param end   數組的最大索引: arr.length - 1* @return 排序好的數組*/
public static int[] quickSort(int arr[], int start, int end) {int pivot = arr[start];int i = start;int j = end;while (i < j) {while ((i < j) && (arr[j] > pivot)) {j--;}while ((i < j) && (arr[i] < pivot)) {i++;}if ((arr[i] == arr[j]) && (i < j)) {i++;} else {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}if (i - 1 > start) arr = quickSort(arr, start, i - 1);if (j + 1 < end) arr = quickSort(arr, j + 1, end);return (arr);
}

示例代碼2:

/*** 快速排序(無返回值)* @param a 需要排序的數組* @param low 數組的最小索引: 0* @param high 數組的最大索引: arr.length - 1*/
public static void quickSort2(int[] a, int low, int high) {int start = low;int end = high;int key = a[low];while (end > start) {//從后往前比較while (end > start && a[end] >= key)//如果沒有比關鍵值小的,比較下一個,直到有比關鍵值小的交換位置,然后又從前往后比較end--;if (a[end] <= key) {int temp = a[end];a[end] = a[start];a[start] = temp;}//從前往后比較while (end > start && a[start] <= key)//如果沒有比關鍵值大的,比較下一個,直到有比關鍵值大的交換位置start++;if (a[start] >= key) {int temp = a[start];a[start] = a[end];a[end] = temp;}//此時第一次循環比較結束,關鍵值的位置已經確定了。左邊的值都比關鍵值小,右邊的值都比關鍵值大,但是兩邊的順序還有可能是不一樣的,進行下面的遞歸調用}//遞歸if (start > low) quickSort2(a, low, start - 1);//左邊序列。第一個索引位置到關鍵值索引-1if (end < high) quickSort2(a, end + 1, high);//右邊序列。從關鍵值索引+1 到最后一個
}

希爾排序算法

(1)基本思想:先將整個待排序的記錄序列分割成為若干子序列分別進行直接插入排序,待整個序列中的記錄“基本有序”時,再對全體記錄進行依次直接插入排序。

/*** 希爾排序* @param a */
private static void shellSort(int[] a) {int dk = a.length / 2;while (dk >= 1) {//類似插入排序,只是插入排序增量是 1,這里增量是 dk,把 1 換成 dk 就可以了for (int i = dk; i < a.length; i++) {if (a[i] < a[i - dk]) {int j;int x = a[i];//x 為待插入元素a[i] = a[i - dk];for (j = i - dk; j >= 0 && x < a[j]; j = j - dk) {//通過循環,逐個后移一位找到要插入的位置。a[j + dk] = a[j];}a[j + dk] = x;//插入}}dk = dk / 2;}
}

歸并排序算法

(1)基本思想:歸并(Merge)排序法是將兩個(或兩個以上)有序表合并成一個新的有序表,即把待排序序列分為若干個子序列,每個子序列是有序的。然后再把有序子序列合并為整體有序序列。

(2)歸并排序:是建立在歸并操作上的一種有效,穩定的排序算法。

什么是歸并操作?

歸并操作,也叫歸并算法,指的是將兩個順序序列合并成一個順序序列的方法。
如 設有數列{6,202,100,301,38,8,1}
初始狀態:6,202,100,301,38,8,1
第一次歸并后:{6,202},{100,301},{8,38},{1},比較次數:3;
第二次歸并后:{6,100,202,301},{1,8,38},比較次數:4;
第三次歸并后:{1,6,8,38,100,202,301},比較次數:4;
總的比較次數為:3+4+4=11;
逆序數為14;

示例代碼:

/*** 歸并排序* @param nums 待排序數組* @param l 開始索引:0* @param h 最大索引:nums.length - 1* @return 排序好的數組*/
public static int[] mergeSort(int[] nums, int l, int h) {if (l == h)return new int[]{nums[l]};int mid = l + (h - l) / 2;int[] leftArr = mergeSort(nums, l, mid); //左有序數組int[] rightArr = mergeSort(nums, mid + 1, h); //右有序數組int[] newNum = new int[leftArr.length + rightArr.length]; //新有序數組int m = 0, i = 0, j = 0;while (i < leftArr.length && j < rightArr.length) {newNum[m++] = leftArr[i] <= rightArr[j] ? leftArr[i++] : rightArr[j++];}while (i < leftArr.length)newNum[m++] = leftArr[i++];while (j < rightArr.length)newNum[m++] = rightArr[j++];return newNum;
}

桶排序算法

(1)基本思想:把數組 arr 劃分為 n 個大小相同子區間(桶),每個子區間各自排序,最后合并 。計數排序是桶排序的一種特殊情況,可以把計數排序當成每個桶里只有一個元素的情況。

(2)排序過程

  • 找出待排序數組中的最大值 max、最小值 min
  • 我們使用 動態數組 ArrayList 作為桶,桶里放的元素也用 ArrayList 存儲。桶的數量為(maxmin)/arr.length+1
  • 遍歷數組 arr,計算每個元素 arr[i] 放的桶
  • 每個桶各自排序

示例代碼:

/*** 桶排序** @param data 待排序數組*/
public static void bucketSort(int data[]){int n = data.length;int bask[][] = new int[10][n];int index[] = new int[10];int max = Integer.MIN_VALUE;for (int i = 0; i < n; i++) {max = max > (Integer.toString(data[i]).length()) ? max : (Integer.toString(data[i]).length());}String str;for (int i = max - 1; i >= 0; i--) {for (int j = 0; j < n; j++) {str = "";if (Integer.toString(data[j]).length() < max) {for (int k = 0; k < max - Integer.toString(data[j]).length(); k++)str += "0";}str += Integer.toString(data[j]);bask[str.charAt(i) - '0'][index[str.charAt(i) - '0']++] = data[j];}int pos = 0;for (int j = 0; j < 10; j++) {for (int k = 0; k < index[j]; k++) {data[pos++] = bask[j][k];}}for (int x = 0; x < 10; x++) index[x] = 0;}
}

基數排序算法

(1)基本思想:將整數按位數切割成不同的數字,然后按每個位數分別比較。

(2)排序過程:將所有待比較數值(正整數)統一為同樣的數位長度,數位較短的數前面補零。然后,從最低位開始,依次進行一次排序。這樣從最低位排序一直到最高位排序完成以后,數列就變成一個有序序列。

(3)代碼示例:

/*** 基數排序* @param number 待排序的數組* @param d 表示最大的數有多少位*/
public static void sort(int[] number, int d) 
{int k = 0;int n = 1;int m = 1; //控制鍵值排序依據在哪一位int[][] temp = new int[10][number.length]; //數組的第一維表示可能的余數0-9int[] order = new int[10]; //數組order[i]用來表示該位是i的數的個數while (m <= d) {for (int i = 0; i < number.length; i++) {int lsd = ((number[i] / n) % 10);temp[lsd][order[lsd]] = number[i];order[lsd]++;}for (int i = 0; i < 10; i++) {if (order[i] != 0)for (int j = 0; j < order[i]; j++) {number[k] = temp[i][j];k++;}order[i] = 0;}n *= 10;k = 0;m++;}
}

分治算法

分治算法基本介紹
分治法(Divide-and-Conquer)是一種很重要的算法。字面上的解釋是"分而治之",就是把一個復雜的問題分成兩個或更多的相同或相似的子問題,再把子問題分成更小的子問題……直到最后子問題可以簡單的直接求解,原問題的解即子問題的解的合并。

這個技巧是很多高效算法的基礎,如排序算法(快速排序,歸并排序),傅立葉變換(快速傅立葉變換)…

在這里插入圖片描述

分治算法的基本實現步驟(分治法在每一層遞歸上都有三個步驟):

  1. **分解:**將原問題分解為若干個規模較小,相互獨立,與原問題形式相同的子問題
  2. **解決:**若子問題規模較小而容易被解決則直接解,否則遞歸地解各個子問題
  3. **合并:**將各個子問題的解合并為原問題的解

漢諾塔問題

分治算法經典問題:漢諾塔問題

漢諾塔的傳說

漢諾塔:漢諾塔(又稱河內塔)問題是源于印度一個古老傳說的益智玩具。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著 64 片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。并且規定,在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個圓盤。

假如每秒鐘一次,共需多長時間呢?移完這些金片需要 5845.54 億年以上,太陽系的預期壽命據說也就是數百億年。真的過了 5845.54 億年,地球上的一切生命,連同梵塔、廟宇等,都早已經灰飛煙滅。

體驗完后,我們來整理下移動盤子的思路(假設有A、B、C柱子):

1、如果只有一個盤,直接可以A->C

2、如果盤子的數量 n >= 2,我就可以看做是兩個盤子。。

  • 最下邊(最大)的盤
  • 上面的盤

因此就可以走三部曲

先把最上面的盤A->B
把最下邊的盤A->C
把B塔的所有盤從B->C

在這里插入圖片描述

代碼示例:

/*** 漢諾塔問題解決* @param discNum 盤子數量* @param a A柱子* @param b B柱子* @param c C柱子*/
public static void towerOfHanoi(int discNum, char a, char b, char c) {// 如果只有一個盤if (discNum == 1) {System.out.println("第1個盤" + a + "->" + c);} else {// 盤的數量 >= 2// 1.上盤A->BtowerOfHanoi(discNum - 1, a, c, b);// 2.下盤A->CSystem.out.println("第" + discNum + "個盤" + a + "->" + c);// 3.把B柱子的所有盤子移至C柱子towerOfHanoi(discNum - 1, b, a, c);}
}

動態規劃算法

引子

背包問題:現有一個背包,容量為4磅。現有如下物品:

在這里插入圖片描述

1、要求達到的目標為裝入的背包的總價值最大,并且重量不超出

2、要求裝入的物品不能重復

3.2、動態規劃算法基本介紹
1、動態規劃(Dynamic Programming)算法(簡稱DP算法)的核心思想是:將大問題劃分為小問題進行解決,從而一步步獲取最優解的處理算法

2、動態規劃算法與分治算法類似,其基本思想也是將待求解問題分解成若干個子問題,先求解子問題,然后從這些子問題的解得到原問題的解

3、與分治法不同的是,適合于用動態規劃求解的問題,經分解得到子問題往往不是互相獨立的。 ( 即下一個子階段的求解是建立在上一個子階段的解的基礎上,進行進一步的求解 )

4、動態規劃可以通過填表的方式來逐步推進,得到最優解

代碼實現背包問題

1、背包問題主要是指一個給定容量的背包、若干具有一定價值和重量的物品,如何選擇物品放入背包使物品的價值最大。其中又分 01 背包和完全背包(完全背包指的是:每種物品都有無限件可用)

2、這里的問題屬于 01 背包,即每個物品最多放一個。而無限背包可以轉化為 01 背包。

3、算法的主要思想:利用動態規劃來解決。每次遍歷到的第 i 個物品,根據w[i] 和 v[i] 來確定是否需要將該物品放入背包中。即對于給定的 n 個物品,設 v[i]、w[i]分別為第 i 個物品的價值和重量,C 為背包的容量。再令 v[i][j]表示在前 i 個物品中能夠裝入容量為 j 的背包中的最大價值。

基于以上設定我們得出:

/*
(1) v[i][0]=v[0][j]=0; //表示 填入表 第一行和第一列是 0
(2) 當 w[i]> j時:v[i][j]=v[i-1][j] // 當準備加入新增的商品的容量大于 當前背包的容量時,就直接使用上一個單元格的裝入策略
(3) 當 j>=w[i]時: v[i][j]=max{v[i-1][j], v[i]+v[i-1][j-w[i]]} // 當準備加入的新增的商品的容量小于等于當前背包的容量,裝入的方式:1. v[i-1][j]: 就是上一個單元格的裝入的最大值2. v[i]: 表示當前商品的價值3. v[i-1][j-w[i]]: 裝入 i-1 商品,到剩余空間 j-w[i]的最大值4. 當 j>=w[i]時: v[i][j]=max{v[i-1][j], v[i]+v[i-1][j-w[i]]}
*/

在這里插入圖片描述

代碼示例:

public static void main(String[] args) {int[] wight = new int[]{1, 4, 3}; // 物品的重量int[] price = new int[]{1500, 3000, 2000}; // 物品的價格int m = 4; // 背包的容量int n = price.length; // 物品的個數// 創建一個二維數組// v[i][j] 表示在前i個物品中能夠裝入容量為j的背包中的最大價值int[][] v = new int[n + 1][m + 1];// 初始化第一行和第一列,這里在本程序中,可以不去處理,因為默認就是0for (int i = 0; i < v.length; i++) {v[i][0] = 0; // 將第一列設置為0}for (int i = 0; i < v.length; i++) {v[0][i] = 0; // 將第一行設置為0}// 為了記錄放入商品的情況,我們定一個二維數組int[][] path = new int[n + 1][m + 1];// 動態規劃處理背包問題// i和j初始都等于1,目的是不處理第一行第一列for (int i = 1; i < v.length; i++) {for (int j = 1; j < v[i].length; j++) {// 公式if (wight[i - 1] > j) { // 因為我們程序i是從1開始的,因此原理公式中的w[i]修改成[i-1]v[i][j] = v[i - 1][j];} else {// 因為 i 是從1開始的,因此公式需要做出調整,如下所示// v[i][j] = Math.max(v[i - 1][j], price[i - 1] + v[i - 1][j - wight[i - 1]]);if (v[i - 1][j] < price[i - 1] + v[i - 1][j - wight[i - 1]]) {v[i][j] = price[i - 1] + v[i - 1][j - wight[i - 1]];// 把當前的情況記錄到pathpath[i][j] = 1;} else {v[i][j] = v[i - 1][j];}}}}// 輸出vfor (int i = 0; i < v.length; i++) {for (int j = 0; j < v[i].length; j++) {System.out.print(v[i][j] + " ");}System.out.println();}// 輸出放入的商品情況int i = path.length - 1; // 行的最大下標int j = path[0].length - 1; // 列的最大下標while (i > 0 && j > 0) {if (path[i][j] == 1) {System.out.printf("第%d個商品放入到背包\n", i);j -= wight[i - 1];}i--;}
}

KMP算法

什么是KMP算法

KMPKnuth、Morris和Pratt首字母的縮寫,KMP也是由這三位學者發明(1977年聯合發表論文)。

KMP主要應用在字符串的匹配,是一個解決模式串在文本串是否出現過,如果出現過,得出最早出現的位置的經典算法。其主要思想是:當出現字符串不匹配時,可以知道之前已經匹配的文本內容,可以利用這些信息避免從頭再去匹配,從而提高匹配效率。

因此如何記錄已經匹配的文本內容,才是KMP的重點~這也使得next數組派上了用場。

KMP算法就利用之前判斷過信息,通過一個 next 數組,保存模式串中前后最長公共子序列的長度,每次回溯時,通過 next 數組找到前面匹配過的位置,省去了大量的計算時間。

在這里插入圖片描述

暴力匹配

現給出一段字符串str1:“硅硅谷 尚硅谷你尚硅 尚硅谷你尚硅谷你尚硅你好”,和一段子字符串str2:“尚硅谷你”。

要求寫出判斷str1是否含有str2的代碼,如果存在就返回第一次出現的位置,如果沒有則返回-1。

說到字符串匹配,我們第一時間想到的是直接遍歷字符串,看看是否存在。這種方法稱為暴力匹配,拋開效率不說,這種方式是最直接,最簡單的方式。

然而暴力匹配也是一種算法,一種解決方案,針對上述問題,我們可以得出暴力匹配算法的思路(假設現在 str1 匹配到 i 位置,子串 str2 匹配到 j 位置):

  • 如果當前字符匹配成功(即 str1[i] == str2[j]),則 i++,j++,繼續匹配下一個字符
  • 如果失配(即 str1[i] != str2[j]),令 i = i - (j - 1),j = 0。相當于每次匹配失敗時,i 回溯,j 被置為 0
  • 用暴力方法解決的話就會有大量的回溯,每次只移動一位,若是不匹配,移動到下一位接著判斷,浪費了大量的時間(不可行!)

代碼示例:

/*** 暴力匹配算法* @param str1* @param str2* @return 返回str2首次出現在str1的位置,匹配不到則返回-1*/
public static int violenceMatch(String str1, String str2) {char[] s1 = str1.toCharArray();char[] s2 = str2.toCharArray();int i = 0; // 指向s1int j = 0; // 指向s2while (i < s1.length && j < s2.length) {if (s1[i] == s2[j]) {i++;j++;} else {// 只要有一個沒有匹配上i = i - (j - 1);j = 0;}}// 判斷是否匹配成功if (j == s2.length) {return i - j;}return -1;
}

main方法中測試暴力匹配:

public class AlgorithmUtils {public static void main(String[] args) {String str1 = "硅硅谷 尚硅谷你尚硅 尚硅谷你尚硅谷你尚硅你好";String str2 = "尚硅谷你";int index = AlgorithmUtils.violenceMatch(str1, str2);if (index != -1) {System.out.printf("第一次出現的位置是%d", index);}}
}

KMP算法實現

前面呢我們已經使用暴力匹配算法,完成了上述問題的求解!也知道了暴力匹配存在效率問題,那么KMP算法又是怎樣實現呢?

為方便闡述,這里我們換個案例:現有兩組字符串

str1 = “BBC ABCDAB ABCDABCDABDE”;
str2 = “ABCDABD”;

要求使用 KMP算法 完成判斷,str1 是否含有 str2,如果存在,就返回第一次出現的位置,如果沒有,則返回-1。

備注:不能使用簡單的暴力匹配算法!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/209565.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/209565.shtml
英文地址,請注明出處:http://en.pswp.cn/news/209565.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《微信小程序開發從入門到實戰》學習四十五

4.4 云函數 云函數是開發者提前定義好的、保存在云端并且將在云端運行的JS函數。 開發者先定義好云函數&#xff0c;再使用微信開發工具將云函數上傳到云空間&#xff0c;在云開發控制臺中可看到已經上傳的云函數。 云函數運行在云端Node.js環境中。 小程序端通過wx.cloud.…

IP地址定位技術為網絡安全建設提供全新方案

隨著互聯網的普及和數字化進程的加速&#xff0c;網絡安全問題日益引人關注。網絡攻擊、數據泄露、欺詐行為等安全威脅層出不窮&#xff0c;對個人隱私、企業機密和社會穩定構成嚴重威脅。在這樣的背景下&#xff0c;IP地址定位技術應運而生&#xff0c;為網絡安全建設提供了一…

Python Selenium 自動登入1688

Python Selenium是一個用于自動化Web瀏覽器操作的庫。它提供了一組功能強大的工具和API&#xff0c;可以模擬用戶在瀏覽器中的行為&#xff0c;并執行各種任務&#xff0c;如點擊、輸入文本、提交表單等。 要使用Python Selenium登錄1688網站&#xff0c;需要進行以下步驟&…

iOS微信小程序虛擬支付解決方案

眾所周知&#xff0c;在IOS微信小程序不支持虛擬支付&#xff0c;一直是困擾IOS開發者、運營最頭疼的問題&#xff0c;主要原因是蘋果不允許IOS微信上架這類產品。導致微信小程序的開發者在IOS上都不能支付虛擬商品&#xff0c;虛擬商品包含了虛擬課程、會員、虛擬書等。 那么…

短視頻ai剪輯分發矩陣系統源碼3年技術團隊開發搭建打磨

如果您需要搭建這樣的系統&#xff0c;建議您尋求專業的技術支持&#xff0c;以確保系統的穩定性和安全性。 在搭建短視頻AI剪輯分發矩陣系統時&#xff0c;您需要考慮以下幾個方面&#xff1a; 1. 技術實現&#xff1a;您需要選擇適合您的需求和預算的技術棧&#xff0c;例如使…

肖sir__ 項目講解__項目數據

項目時間&#xff1a; 情況一&#xff1a;項目時間開始到上線的時間&#xff0c;這個時間一般比較長&#xff08;一年&#xff0c;二年&#xff0c;三年&#xff09; 情況二&#xff1a;項目的版本的時間或則是周期&#xff08;1個月&#xff0c;2個月&#xff0c;3個月&…

機器人、智能小車常用的TT電機/310電機/370電機選型對比

在制作智能小車或小型玩具時&#xff0c;在電機選型上一些到各種模糊混淆的概念&#xff0c;以及各種錯綜復雜的電機參數&#xff0c;本文綜合對比幾種常用電機的參數及特性適應范圍&#xff0c;以便快速選型&#xff0c;注意不同生產廠家的電機參數規則會有較大差異。 普通TT…

論文閱讀:PointCLIP: Point Cloud Understanding by CLIP

CVPR2022 鏈接&#xff1a;https://arxiv.org/pdf/2112.02413.pdf 0、Abstract 最近&#xff0c;通過對比視覺語言預訓練(CLIP)的零鏡頭學習和少鏡頭學習在2D視覺識別方面表現出了鼓舞人心的表現&#xff0c;即學習在開放詞匯設置下將圖像與相應的文本匹配。然而&#xff0c;…

【ET8】2.ET8入門-ET框架解析

菜單欄相關&#xff1a;ENABLE_DLL選項 ET->ChangeDefine->ADD_ENABLE_DLL/REMOVE_ENABLE_DLL 一般在開發階段使用Editor時需要關閉ENABLE_DLL選項。該選項關閉時&#xff0c;修改腳本之后&#xff0c;會直接重新編譯所有的代碼&#xff0c;Editor在運行時會直接使用最…

免費網頁抓取工具大全【附下載和工具使用教程】

在當今信息爆炸的時代&#xff0c;獲取準確而豐富的數據對于企業決策和個人研究至關重要。而網頁抓取工具作為一種高效獲取互聯網數據的方式&#xff0c;正逐漸成為大家解決數據需求的得力助手。本文將深入探討網頁抓取工具的種類&#xff0c;并為大家提供簡單實用的頁面采集教…

(企業項目)SpringBoot3整合校驗框架validation

在Spring Boot項目中使用校驗框架validation可以讓我們更方便地實現數據校驗和錯誤提示。下面是Spring Boot集成校驗框架validation的步驟。 添加依賴 在項目的pom.xml文件中添加validation依賴&#xff1a; <dependency><groupId>org.springframework.boot</…

C# 實現Lru緩存

C# 實現Lru緩存 LRU 算法全稱是最近最少使用算法&#xff08;Least Recently Use&#xff09;&#xff0c;是一種簡單的緩存策略。 通常用在對象池等需要頻繁獲取但是又需要釋放不用的地方。 代碼實現的基本原理就是使用鏈表&#xff0c;當某個元素被訪問時&#xff08;Get或…

windows安裝protoc、protoc-gen-go、protoc-gen-go-grpc

文章目錄 一、 protoc二、protoc-gen-go三、protoc-gen-go-grpc 一、 protoc 1&#xff0c;下載&#xff1a;https://github.com/google/protobuf/releases 下載對應的protoc&#xff0c;注意選擇windows 2&#xff0c;下好之后解壓就行&#xff0c;然后把bin目錄加入到環境…

【異常】淺析異常體系及為什么一定會執行finally塊代碼

異常體系&#xff1a; &#xff08;1&#xff09;所有異常&#xff08;Exception&#xff09;、錯誤&#xff08;Error&#xff09;都繼承自異常中的基類&#xff1a;Throwable。而異常又可以分為檢查異常&#xff08;Checked Exception&#xff09;、非檢查異常&#xff08;Un…

msvcp100.dll丟失的常見原因/msvcp100.dll丟失的解決方法分享

在計算機使用過程中&#xff0c;我們經常會遇到一些錯誤提示&#xff0c;其中之一就是“msvcp100.dll丟失”。這個錯誤提示通常出現在運行某些程序或游戲時&#xff0c;給使用者帶來了很大的困擾。那么&#xff0c;究竟是什么原因導致了msvcp100.dll文件的丟失呢&#xff1f;本…

ubuntu22.04在opencv4的基礎上安裝opencv3

安裝opencv4 首先在ubuntu22.04上安裝opencv4&#xff0c;可以參考之前的博客ubuntu22.04安裝opencv4和opencv_contrib-CSDN博客 安裝opencv3 由于有使用opencv3的需求&#xff0c;所以需要繼續安裝opencv3 ; 安裝編譯 這里安裝的版本是opencv3.4.5&#xff0c;大致安裝思…

STM32F1之CAN介紹

目錄 ?編輯 1. CAN 是什么&#xff1f; 2. 總線拓撲圖 3. CAN 的特點 4. CAN 協議的基本概念 1. CAN 是什么&#xff1f; CAN 是 Controller Area Network 的縮寫&#xff08;以下稱為 CAN&#xff09;&#xff0c;是 ISO*1 國際標準化的串行通信協議。 在當前的汽車產…

javaWebssh學生系統myeclipse開發mysql數據庫MVC模式java編程計算機網頁設計

一、源碼特點 java ssh學生管理系統是一套完善的web設計系統&#xff08;系統采用ssh框架進行設計開發&#xff09;&#xff0c;對理解JSP java編程開發語言有幫助&#xff0c;系統具有完整的源代碼和數據庫&#xff0c;系統主要采用B/S模 式開發。開發環境為TOMCAT7.0,My…

前端開發中,Web Storage的存儲數據的方法localstorage和sessionStorage的使用及區別

在 Web瀏覽器中存儲數據以改善用戶體驗和提升Web應用程序性能是非常常見的。在大多數情況下&#xff0c;可供我們使用就是LocalStorage和SessionStorage。 本文中&#xff0c;我們將會從安全性和用戶體驗兩個方面對SessionStorage和LocalStorage進行評估。然后我們將討論如何根…

Linux驅動安裝遇到的問題(Kernel configuration is invalid)(Invalid module format)

Linux驅動編譯安裝遇到的問題&#xff08;Kernel configuration is invalid&#xff09;&#xff08;Invalid module format&#xff09; 前言1. Kernel configuration is invalid2. Invalid module format2.1 第一種情況&#xff1a;內核模塊編譯的環境與現在insmod想要運行的…