日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

经典算法-并查集、快速排序、字典序算法、二分搜索、牛顿开方法、求质数(筛选法)、编辑距离、滑动窗口、异或求重、长除法

發布時間:2023/12/20 编程问答 28 豆豆

目錄

??????????????

并查集

快速排序

字典序算法

二分搜索

開根號-牛頓開方法

求質數

編輯距離

滑動窗口

異或求重

長除法


???????

并查集

并查集用于解決相同元素集合動態連接的快速構建算法

例:求相等集合a=b,e=d,d=b

初始時,ab為一集合,ed為一集合,又d=b,故應將abed變為一集合,之后e=a就是顯而易見的事了

并查集利用構建樹形結構的方式,每個元素有上級,上級有上級,最高級的上級為其本身,通過查看兩個元素的最高級是否相同來判斷兩元素是否屬于同一集合

即,每個集合為一棵樹,判斷兩個元素是否屬于同一個集合只用判斷其樹根是否相同即可

初始時有數組pre[],pre[i]表示元素i的上一級

find(int x)用于找出元素x的最高級,即樹根

  • ?int find(int x){
  • ? ? ? ? ? ? while(x!=pre[x]){
  • ? ? ? ? ? ? ? ? x=pre[x];
  • ? ? ? ? ? ? } ??
  • ? ? ? ? ? ? return x;
  • ? ? ? ? }
  • union(int x,int y)用于將x,y所代表的兩個集合合并

  • ?void union(int x,int y){
  • ? ? ? ? ? ? int a=find(x);
  • ? ? ? ? ? ? int b=find(y);
  • ? ? ? ? ? ? pre[b]=a;
  • ? ? ? ? }
  • 例題(leetcode-990):

    給定一個由表示變量之間關系的字符串方程組成的數組,每個字符串方程?equations[i]?的長度為?4,并采用兩種不同的形式之一:"a==b"?或?"a!=b"。在這里,a 和 b 是小寫字母(不一定不同),表示單字母變量名。

    只有當可以將整數分配給變量名,以便滿足所有給定的方程時才返回?true,否則返回?false。?

    示例 1:

    輸入:["a==b","b!=a"] 輸出:false 解釋:如果我們指定,a = 1 且 b = 1,那么可以滿足第一個方程,但無法滿足第二個方程。沒有辦法分配變量同時滿足這兩個方程。

    示例 3:

    輸入:["a==b","b==c","a==c"] 輸出:true

    示例 5:

    輸入:["c==c","b==d","x!=z"] 輸出:true

    提示:

  • 1 <= equations.length <= 500
  • equations[i].length == 4
  • equations[i][0]?和?equations[i][3]?是小寫字母
  • equations[i][1]?要么是?'=',要么是?'!'
  • equations[i][2]?是?'='
  • class Solution {//使用一下傳統并查集private ?int[] pre=new int[2560];//存儲其上一級,最高級為其本身,成為代理人//發現x所在集合的最高代理人private int find(int x){while(x!=pre[x]){x=pre[x];} ??return x;}//兩者應該屬于同一伙,合并,為使其成為樹狀結構,加快查找速度,將最高代理人合并private void union(int x,int y){int a=find(x);int b=find(y);if(a!=b){pre[b]=a;}}public boolean equationsPossible(String[] equations) {for(int i=0;i<2560;i++){pre[i]=i;//初始化}for(String s:equations){int l=s.charAt(0);int r=s.charAt(3);if(s.charAt(1)=='='&&find(l)!=find(r)){union(l,r);}}for(String s:equations){int l=s.charAt(0);int r=s.charAt(3);if(s.charAt(1)=='!'&&find(l)==find(r)){return false;}}return true;}}

    參考:https://blog.csdn.net/liujian20150808/article/details/50848646

    快速排序

    快速排序以分治法為基本思想,遞歸為基本表現形式。

    對于一個數組nums,傳遞參數left,right,為范圍,以第一個數(nums[0])為key,將所有<=key的數放在左邊,所有>key的數放在右邊。

    i=left,j=right,向前推進i直到找到第一個>key的數,向后推進直到找到第一個<=key的數

    交換i,j的數的位置直到i==j

    退出循環,此時i==j,核查nums[i]與key,保證<=i的數全部<=key,>j的數全部>j。因為以nums[0]為基準,nums[0]不能在參加遞歸運算,交換nums[i]與nums[0],繼續遞歸,范圍為[left,i-1],[j,right]

    遞歸的結束條件即為left>=right

    ? ? private void sort(int[] nums,int left,int right){if(left>=right)return ;int i=left,j=right;int key=nums[left];while(i<j){while(i<j&&nums[j]>key){j--;}while(i<j&&nums[i]<=key){i++;}int tmp=nums[i];nums[i]=nums[j];nums[j]=tmp;}if(nums[i]<=key)j++;else i--;nums[left]=nums[i];nums[i]=key;//基準數不再參與數據處理sort(nums,left,i-1);sort(nums,j,right);}

    字典序算法

    字典序即按照a-zA-Z0-9的順序對由這些元素組成的串的從小到大的全排列。

    如[1,2,3]進行全排列,將1,2,3組成數字,字典序就相當于按所有組成數字從小到大進行排列。

    123->132->213->231->312->321

    字典序算法可用于全排列(n!)生成

    字典序算法的步驟為:

    • 1.從右至左找到第一個左鄰小于右鄰,記錄左鄰位置i
    • 2.從右至左找到第一個大于左鄰的數,即位置為j,交換num[i],num[j]
    • 3.對位置i之后的所有數進行排列

    例題(leetcode-31)

    實現獲取下一個排列的函數,算法需要將給定數字序列重新排列成字典序中下一個更大的排列。

    如果不存在下一個更大的排列,則將數字重新排列成最小的排列(即升序排列)。

    必須原地修改,只允許使用額外常數空間。

    以下是一些例子,輸入位于左側列,其相應輸出位于右側列。
    1,2,3?→?1,3,2
    3,2,1?→?1,2,3
    1,1,5?→?1,5,1

    class Solution {public void nextPermutation(int[] nums) {//考察字典序算法,字典序可用于生成全排列//字典序算法步驟為://1.從右至左找到第一個左鄰小于右鄰,記錄左鄰位置i//2.從右至左找到第一個大于左鄰的數,即位置為j,交換num[i],num[j]//3.對位置i之后的所有數進行排列//如果沒找到i則說明已經是最大的排列數int a=-1;//1.從右至左找到第一個左鄰小于右鄰,記錄左鄰位置ifor(int i=nums.length-1;i>0;i--){if(nums[i-1]<nums[i]){a=i-1;break;}}if(a==-1){sort(nums,0,nums.length-1);return ;}//2.從右至左找到第一個大于左鄰的數,即位置為j,交換num[i],num[j]for(int i=nums.length-1;i>a;i--){if(nums[i]>nums[a]){int temp=nums[i];nums[i]=nums[a];nums[a]=temp;sort(nums,a+1,nums.length-1);return ;}}}private void sort(int[] nums,int left,int right){if(left>=right)return ;int i=left,j=right;int key=nums[left];while(i<j){while(i<j&&nums[j]>key){j--;}while(i<j&&nums[i]<=key){i++;}int tmp=nums[i];nums[i]=nums[j];nums[j]=tmp;}if(nums[i]<=key)j++;else i--;nums[left]=nums[i];nums[i]=key;//基準數不再參與數據處理sort(nums,left,i-1);sort(nums,j,right);} }

    二分搜索

    太經典了,看代碼即可,nums為已排序數組

    ? ? ? ? int left=0,right=nums.length-1;while(left<=right){int med=(left+right)/2;if(nums[med]==target)return med;else if(nums[med]<target){left=med+1;}else{right=med-1;}}

    開根號-牛頓開方法

    實際上就是完成一個sqrt()函數,計算機完成開根號的運算,大部分使用牛頓迭代法。

    假設a為要開方的數,那么x就是答案,即求f(x)=0時,x為何值

    選取函數上一點(t,t^2-a),對于該點,求切線,切線上在x軸方向上的零點必定逼近于結果

    切線的斜率對原函數求導即可,k=2t,該切線經過點(t,t^2-a),求切線在x軸方向上的零點,即(t^2+a)/2t

    以該點繼續迭代即可不斷逼近與結果

    ? ? public int mySqrt(int x) {//牛頓迭代法//y=res^2-x,選取點(a,a^2-x)做切點//斜率即求導數k=2a,令y=2ares`+t//帶入化簡,零點為res`=(a^2+x)/2a,繼續迭代if(x==0)return 0;if(x<=3)return 1;long current=x/2;while(current*current>x){current=((current+x/current)/2);}return (int)current;}

    當然,原理上是這么算的,實際上想要運行的更快還有一些技巧

    關于這個方法,還有一個神奇的數字

    0x5f3759df

    ?雷神之錘

    參看:https://www.cnblogs.com/pkuoliver/archive/2010/10/06/1844725.html

    求質數

    有兩種方法

    1.暴力求解,對每一個數進行判斷,判斷到sqrt(n)

    for(int i=2;i<=n;i++){for(int j=2;j<=sqrt(i);j++){if(i%j==0)==>i不是質數;break;}}

    2.篩選法,對于2來說,2的倍數一定不是質數,對于3來說,3的倍數一定不是質數。。開一個int[n]的數組,對于2,3...n

    2是質數,但2的倍數不是,打表,每次先判斷當前是否被打上去,如果是直接跳過,否則是質數,打表。

    boolean[] check=new boolean[n+1]int tot = 0;for (int i = 2; i <= n; ++i) {if (!check[i]){prime[tot++] = i;}for (int j = i+i; j <= n; j += i){check[j] = true;}}

    編輯距離

    ? ? ? ? 有兩個具有相同性質的物質可以互相轉換,字符串A轉換成字符串B,A,B都由字符構成,給定基本條件,求A能轉換成B所需要的最小步驟,這個問題比較抽象,而所用的就是編輯距離算法,實際上還是動態規劃算法。

    ? ? ? ? 編輯距離是針對兩個字符串(例如英文字)的差異程度的量化量測,量測方式是看至少需要多少次的處理才能將一個字符串變成另一個字符串。編輯距離可以用在自然語言處理中,例如拼寫檢查可以根據一個拼錯的字和其他正確的字的編輯距離,判斷哪一個(或哪幾個)是比較可能的字。DNA也可以視為用A、C、G和T組成的字符串,因此編輯距離也用在生物信息學中,判斷二個DNA的類似程度。(來自百度百科)

    例題(leetcode-72)

    給定兩個單詞?word1 和?word2,計算出將?word1?轉換成?word2 所使用的最少操作數?。

    你可以對一個單詞進行如下三種操作:

    插入一個字符
    刪除一個字符
    替換一個字符
    示例?1:

    輸入: word1 = "horse", word2 = "ros"
    輸出: 3
    解釋:?
    horse -> rorse (將 'h' 替換為 'r')
    rorse -> rose (刪除 'r')
    rose -> ros (刪除 'e')

    假設dp[i][j]表示前i個字符轉換成前j個字符所需要的最短距離

    對于當前字符word1[i]與word2[j]來說,

    如果word[i]==word[j],顯然 dp[i][j]=dp[i-1][j-1]

    否則,有三種方法可以對當前字符進行處理。

    • 1.在前i個字符前插入一個字符,顯然我們不知道插到哪里合適,但是如果插入一個字符與word2[j]相同,那么就至少是最小變換中的一種,因為如果插入到別的地方,當前字符還是和word2[j]不同,還要執行變換操作,而插入字符放在最前面,那么dp[i][j]=1+dp[i][j-1](因為插入字符和word2[j]相同)
    • 2.在前i個字符中刪除一個字符,顯然,刪誰都是可以的,但是因為word1[i]和word2[j]不相同,那么刪除word1[i]至少是最小變換中的一種,即dp[i][j]=1+dp[i-1][j]
    • 3.替換一個字符,替換word1[i]=word2[j],則dp[i][j]=1+dp[i-1][j-1]

    由以上推斷就可以寫動歸代碼,注意底層條件的初始設置。

    class Solution {public int minDistance(String word1, String word2) {int[][] dp=new int[word1.length()+1][word2.length()+1];//初始化底層條件for(int i=1;i<=word1.length();i++){dp[i][0]=i;}for(int i=1;i<=word2.length();i++){dp[0][i]=i;}for(int i=0;i<word1.length();i++){for(int j=0;j<word2.length();j++){if(word1.charAt(i)==word2.charAt(j)){dp[i+1][j+1]=dp[i][j];}else{dp[i+1][j+1]=1+Math.min(Math.min(dp[i][j+1],dp[i+1][j]),dp[i][j]);}}}return dp[word1.length()][word2.length()];} }

    滑動窗口

    這是一個非常經典的思想,常用于在給定的范圍中尋求包含的子范圍。

    滑動窗口維護兩個指針:left,right

    最開始left和right都處于最左邊,right向右滑動擴大窗口直到子窗口[left...right]已滿足條件

    這時就要開始動左指針left,對于left當前狀態對應的元素,判斷是否能將其拋出,如果能left向右滑動,即縮小窗口,同時再次進行判斷,如果不能則動右指針right擴大窗口。簡而言之,right擴大窗口,left縮小窗口,整個窗口一次遍歷時就能遍歷到所有符合條件的子窗口。

    leetcode官方描述:

    • 初始,left指針和right指針都指向SS的第一個元素.
    • 將 right 指針右移,擴張窗口,直到得到一個可行窗口,亦即包含TT的全部字母的窗口。
    • 得到可行的窗口后,將left指針逐個右移,若得到的窗口依然可行,則更新最小窗口大小。
    • 若窗口不再可行,則跳轉至 22。

    例題(leetcode-76)

    給你一個字符串 S、一個字符串 T,請在字符串 S 里面找出:包含 T 所有字母的最小子串。

    示例:

    輸入: S = "ADOBECODEBANC", T = "ABC"
    輸出: "BANC"
    說明:

    如果 S 中不存這樣的子串,則返回空字符串 ""。
    如果 S 中存在這樣的子串,我們保證它是唯一的答案。

    class Solution {public String minWindow(String s, String t) {//暴力法O(n*2*m),超時//使用滑動窗口,left縮減窗口,right擴大窗口,窗口大小可動態變化Map<Character,Integer>t2=new HashMap<>();for(char c:t.toCharArray()){t2.put(c,t2.getOrDefault(c,0)+1);}if(!check(getMap(s),t2))return ""; int left=0;int right=t.length()-1;int ls=0;int rs=s.length()-1;//t1也跟著動態變化Map<Character,Integer>t1=new HashMap<>();for(char c:s.substring(0,t.length()).toCharArray()){t1.put(c,t1.getOrDefault(c,0)+1);}while(right<s.length()){if(check(t1,t2)){//滑動窗口包含t,收縮滑動窗口if(right-left<rs-ls){rs=right;ls=left;}t1.put(s.charAt(left),t1.get(s.charAt(left))-1);left++;continue;}//不包含,擴展滑動窗口right++;if(right<s.length())t1.put(s.charAt(right),t1.getOrDefault(s.charAt(right),0)+1);}return s.substring(ls,rs+1);}private Map<Character,Integer> getMap(String s){Map<Character,Integer>t1=new HashMap<>();for(char c:s.toCharArray()){t1.put(c,t1.getOrDefault(c,0)+1);}return t1;}//t1完全包含t2private boolean check(Map<Character,Integer>t1,Map<Character,Integer>t2){for(char c:t2.keySet()){if(!t1.containsKey(c))return false;if(t1.get(c)<t2.get(c))return false;}return true;} }

    異或求重

    ? ? 異或的性質:

    ? ? 1、交換律:a^b = b^a;

    ? ? 2、結合律:(a^b)^c = a^(b^c);

    ? ? 3、對于任意的a:a^a=0,a^0=a,a^(-1)=~a

    ? ? ? ? 由以上性質可以得出一個重要推導:a^b^c^d^a^k =?b^c^d^k^(a^a) =?b^c^d^k^0 =?b^c^d^k,即如果有多個數異或,其中有重復的數,則無論這些重復的數是否相鄰,都可以根據異或的性質將其這些重復的數消去。如果有偶數個數則異或后為0,如果為奇數個,則異或后只剩一個。(引用于:https://blog.csdn.net/ns_code/article/details/27568975

    ?1、1-1000放在含有1001個元素的數組中,只有唯一的一個元素值重復,其它均只出現一次。每個數組元素只能訪問一次,設計一個算法,將它找出來;不用輔助存儲空間,能否設計一個算法實現?

    ????當然,這道題,可以用最直觀的方法來做,將所有的數加起來,減去1+2+3+...+1000的和,得到的即是重復的那個數,該方法很容易理解,而且效率很高,也不需要輔助空間,唯一的不足時,如果范圍不是1000,而是更大的數字,可能會發生溢出。

    ????我們考慮用異或操作來解決該問題。現在問題是要求重復的那個數字,我們姑且假設該數字式n吧,如果我們能想辦法把1-1000中除n以外的數字全部異或兩次,而數字n只異或一次,就可以把1-1000中出n以外的所有數字消去,這樣就只剩下n了。我們首先把所有的數字異或,記為T,可以得到如下:

    T = 1^2^3^4...^n...^n...^1000 = 1^2^3...^1000(結果中不含n)

    ????而后我們再讓T與1-1000之間的所有數字(僅包含一個n)異或,便可得到該重復數字n。如下所示:

    T^(a^2^3^4...^n...^1000) = T^(T^n) = 0^n = n

    ????2、一個數組中只有一個數字出現了一次,其他的全部出現了兩次,求出這個數字。

    ????明白了上面題目的推導過程,這個就很容易了,將數組中所有的元素全部異或,最后出現兩次的元素會全部被消去,而最后會得到該只出現一次的數字。

    長除法

    用于大精度除法求小數

    模擬除法中,小數上的商可以重復,或陷入無限循環(小數循環節),而商實際上是由上一次剩下的模數來決定的,商可以重復而模數不能重復,一旦模數開始重復就代表循環節開始出現

    例題:leetcoed分數到小數

    給定兩個整數,分別表示分數的分子?numerator 和分母 denominator,以字符串形式返回小數。

    如果小數部分為循環小數,則將循環的部分括在括號內。

    示例 1:

    輸入: numerator = 1, denominator = 2 輸出: "0.5"

    示例?2:

    輸入: numerator = 2, denominator = 1 輸出: "2"

    示例?3:

    輸入: numerator = 2, denominator = 3 輸出: "0.(6)" class Solution {public String fractionToDecimal(int numerato, int denominato) {//模擬除法,由題意判斷不會出現無限不循環小數//***********模擬長除法:(商的)小數循環節出現則每次除下的模數也會重復出現//原理:模數一旦重復則代表要出現循環節if(numerato==0)return "0";char flag='+';if((numerato>0&&denominato<0)||(numerato<0&&denominato>0))flag='-';long numerator=Math.abs((long)numerato);//不用long會溢出long denominator=Math.abs((long)denominato);String res="";//能夠整除if(numerator>=denominator&&numerator%denominator==0){return flag=='+'?String.valueOf(numerator/denominator):'-'+String.valueOf(numerator/denominator);}//不能夠整除,注意符號Map<Long,Integer>map=new HashMap<>();//記錄模數與每次除下的商所在的位置res+=numerator/denominator+".";numerator%=denominator;while(true){//結束條件:能夠除盡或者陷入無限循環(模數重復出現)if(map.containsKey(numerator)){res=res.substring(0,map.get(numerator))+"("+res.substring(map.get(numerator))+")";break;}map.put(numerator,res.length());//放模數numerator*=10;res+=numerator/denominator;//System.out.println(numerator+" "+denominator);numerator%=denominator;//模數更新if(numerator==0){break;}}return flag=='+'?res:'-'+res;}}

    注意對于int除法來說為保證能求得準確精度應該使用long類型,否則模數一直*10后面可能會溢出

    總結

    以上是生活随笔為你收集整理的经典算法-并查集、快速排序、字典序算法、二分搜索、牛顿开方法、求质数(筛选法)、编辑距离、滑动窗口、异或求重、长除法的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 亚洲高清av在线 | 我的公把我弄高潮了视频 | 精品少妇白浆小泬60P | 国产精品秘 | 亚洲一区中文字幕永久在线 | 国产精品亚洲一区 | www.综合色| 国产一区二区免费在线观看 | 国产内谢 | 91久久精品一区二区三区 | 亚洲精品天天 | 全黄一级裸片视频 | 国产精品一区二区欧美 | 青青草精品在线视频 | 久久一级免费视频 | 久久久久久国产精品免费播放 | 最新av导航| 日韩人妻无码精品久久久不卡 | 最近日韩中文字幕 | 午夜裸体性播放 | 婷婷丁香九月 | 精品国产麻豆 | 人人干人人舔 | 黄色片在哪里看 | 少妇在线观看 | 日韩性网站 | 精品福利一区二区三区 | 亚洲 激情 | 久久亚洲一区 | 国产精品久久久久久久久久小说 | 欧美美女黄色 | 一级黄色毛毛片 | 最新国产网站 | 视频区图片区小说区 | 精品国产一区二区三区性色av | av夜夜| 亚洲国产永久 | 婷婷五月花| 领导揉我胸亲奶揉下面 | 18色av | 亚洲女人的天堂 | 午夜av在线播放 | 日韩精品视频在线观看免费 | 风韵丰满熟妇啪啪区老熟熟女 | 国产日韩av在线播放 | 粗了大了 整进去好爽视频 日本女优中文字幕 | 一区二区三区伦理片 | 日本少妇一区二区三区 | 亚洲国产精品成人无久久精品 | 日韩国产中文字幕 | 91一区二区三区在线观看 | 日本丰满少妇裸体自慰 | 亚洲性视频网站 | 男生操女生逼逼 | 91午夜交换视频 | 91免费看 | 久久久久久久一区二区三区 | 午夜精品久久久久久久第一页按摩 | 欧美操大逼| 欧美日韩免费在线 | 国产女人在线视频 | 国产做a视频 | 97伊人| 欧美黄色成人 | 成人动漫免费在线观看 | 天天看天天操 | 日韩色在线观看 | 哪个网站可以看毛片 | 日韩欧美视频网站 | 中文字字幕 | 国产奶头好大揉着好爽视频 | 国产香蕉一区 | 国产一级片精品 | 亚洲ⅴ国产v天堂a无码二区 | 欧美激情在线观看 | 亚洲裸体视频 | 日本老年老熟无码 | 在线看片黄 | 奇米在线777 | 国产亚洲无码精品 | 国产又粗又猛又色又 | 成熟女人毛片www免费版在线 | 爱爱高潮视频 | av网站在线免费 | 成人精品视频99在线观看免费 | 一本视频| 日本一区二区在线不卡 | 九九九在线视频 | 中文在线一区 | 国产欧美日韩综合精品一区二区三区 | 日韩精品视频免费看 | 一道本在线播放 | 国产免费av一区二区三区 | 黄色操人视频 | 中国特级黄色大片 | 亚洲精品视频在线免费 | 色一区二区三区 | 午夜精品久久久久久毛片 | 中文字幕视频二区 |