清明不當心就拖了兩天沒更了~~java
這是十道算法題的第二篇了~上一篇回顧:十道簡單算法題git
最近在回顧之前使用C寫過的數據結構和算法的東西,發現本身的算法和數據結構是真的薄弱,如今用Java改寫一下,重溫一下。算法
只能說慢慢積累吧~下面的題目難度都是簡單的,算法的大佬可直接忽略這篇文章了~入門或者算法薄弱的同窗可參考一下~數組
不少與排序相關的小算法(合併數組、獲取數字每位值的和),我都沒有寫下來了,由於只要會了歸併排序(合併數組),會了桶排序(獲取數字每位的值),這些都不成問題了。若是還不太熟悉八大基礎排序的同窗可看:【八大基礎排序總結】微信
因爲篇幅問題,每篇寫十道吧~數據結構
若是有錯的地方,或者有更好的實現,更恰當的理解方式但願你們不吝在評論區留言哦~你們多多交流dom
刪除下標爲k的元素數據結構和算法
思路:數組後一位往前覆蓋便可~測試
/** * 刪除下標爲k的元素 */ public static void deleteK() { //固定的常量(比數組元素的個數要大) int N = 10; int[] arrays = new int[N]; //對數組進行初始化 for (int i = 0; i < 8; i++) { arrays[i] = i; } //要刪除下標 int k = 7; for (int i = k; i < N - 1; i++) { arrays[i] = arrays[i + 1]; } System.out.println("公衆號:Java3y" + arrays); }
給你一個長度爲n的數組,其中有一個數字出現的次數至少爲n/2,找出這個數字優化
這道題能夠用棧的思想來作:
/** * 找出經常使用的數字: * 給你一個長度爲n的數組,其中有一個數字出現的次數至少爲n/2,找出這個數字 */ public static void findMajorityElement(int[] arrays) { //構建一個靜態棧 int[] stack = new int[arrays.length]; // 棧的front指針 int front = -1; // 遍歷給出的數組 for (int i = 0; i < arrays.length; i++) { // 判斷該棧爲空,那麼直接將元素入棧 if (front == -1) { stack[++front] = arrays[i]; } else if (stack[front] == arrays[i]) { // 該元素是否與棧的元素一致-->繼續入棧 stack[++front] = arrays[i]; } else { // 只要不一致,就出棧 front--; } } // 只要該數字出現次數大於數組長度的2/1,那麼留下來的數字確定在棧頂中 System.out.println("關注公衆號:Java3y--->" + stack[0]); }
優化:
public static void findMajorityElement2(int[] arrays) { // 裝載棧的元素 int candidate = -1; // 棧的大小(長度) int count = 0; // 遍歷給出的數組 for (int i = 0; i < arrays.length; i++) { // 判斷該棧爲空,那麼直接將元素入棧 if (count == 0) { candidate = arrays[i]; count++; } else if (candidate == arrays[i]) { // 該元素是否與棧的元素一致-->入棧(棧多一個元素) count++; } else { // 只要不一致-->出棧(棧少一個元素) count--; } } // 只要該數字出現次數大於數組長度的2/1,那麼留下來的數字確定在棧頂中 System.out.println("關注公衆號:Java3y--->" + candidate); }
給你一個數組{0,1,2,3,....n},其中有一個數字缺失,請把缺失的數字找出來
思路:
/** * 找到缺失的數字 * * @param arrays */ public static void missingNumber(int[] arrays) { // 定義要填充到新數組的數字(隨意) int randomNumber = 89898980; // 建立一個新的數組(比已缺失的數組多一個長度) int[] newArrays = new int[arrays.length + 1]; // 填充特殊的數字進新數組中 for (int i = 0; i < newArrays.length; i++) { // 隨意填充數組到新數組中 newArrays[i] = randomNumber; } // 遍歷題目的數組並使用index替代掉新數組的元素 for (int i = 0; i < arrays.length; i++) { // 題目數組的值[0,1,2,3,4,...n]其中有一個缺失 int index = arrays[i]; // 從新填充到新數組上,index對應着題目數組的值 newArrays[index] = 3333333; } // 遍歷新數組,只要還有值爲89898980,那麼那個就是缺失的數字 for (int i = 0; i < newArrays.length; i++) { if (newArrays[i] == randomNumber) { System.out.println("關注公衆號:Java3y---->缺失的數字是:" + i); } } }
結果:
優化:
{0,1,2,3,4,5,....n}
其中缺失一個數字,要把缺失的數字找出來...咱們能夠回顧一下高中學過的等差求和公式:Sn=(a1+an)n/2
{0,1,2,3}
--->(0+3)*4/2
--->6,若是此時缺失的是2呢,就是說題目的給出的數組是:{0,1,3}
,咱們利用等差公式求和以後減去數組每一個元素,最後剩下的數就是缺失的數字!6-1-3-0
--->2因此,咱們能夠寫出這樣的代碼:
/** * 利用等差公式找到缺失的數字 * * @param arrays */ public static void missingNumber2(int[] arrays) { // 套用等差求和公式 int sum = (arrays[0] + arrays[arrays.length - 1]) * (arrays.length + 1) / 2; // 遍歷數組,得出的sum減去數組每一位元素,最後便是缺失的數字 for (int value : arrays) { sum = sum - value; } System.out.println("關注公衆號:Java3y---->缺失的數字是:" + sum); }
結果:
將一個數組的元素,其中是0的,放在數組的最後
思路:
arr[i-zero]
的代碼實現:
/** * 移動元素0到數組最後 * * @param arrays */ public static void moveZero(int[] arrays) { // 記錄該數組有多少個0元素 int zero = 0; for (int i = 0; i < arrays.length; i++) { // 只要元素不爲0,那麼就往前面移動 if (arrays[i] != 0) { arrays[i - zero] = arrays[i]; } else { // 若是爲0,那麼zero ++ zero++; } } // 1. 前面已經將非0的元素移動到數組的前面了 // 2. 將爲0的元素填滿數組,填充的位置就從length - zero開始 int j = arrays.length - zero; while (j < arrays.length) { arrays[j] = 0; j++; } System.out.println("關注公衆號:Java3y---->" + arrays); }
結果:
還能夠換種思路(差異不大):將數組分紅幾個部分:在j以前的沒有0,j到i全是0,i後面尚未遍歷
代碼實現:
/** * 移動元素0到數組最後 * * @param arrays */ public static void moveZero2(int[] arrays) { // 在j前面的元素都不是0 int j = 0; for (int i = 0; i < arrays.length; i++) { if (arrays[i] != 0) { // 跟j進行交換,保證j的前面都不是0 int temp = arrays[i]; arrays[i] = arrays[j]; arrays[j] = temp; j++; } } // 直至i遍歷完畢後,j前面都不是0,j-i都是0(這就完成咱們的任務了) System.out.println("關注公衆號:Java3y---->" + arrays); }
結果仍是同樣的:
給你一個數組,除了一個數字外,其餘的數字都出現了兩次,請把這個只出現一次的數字找出來。
思路:
/** * 找出數組的單個數字 * @param nums * @return */ public static void singleNumber(int[] nums) { for (int i = 0; i < nums.length; i++) { int count = countNumber(nums, nums[i]); // 若是該元素只出現一次,那麼就是它了! if (count == 1) { System.out.println("關注公衆號:Java3y--->單一的元素是:" + nums[i]); return ; } } } /** * 找出每一個元素出現的次數 * @param nums 數組 * @param value 想知道出現次數的元素 */ public static int countNumber(int[] nums,int value) { int count = 0; for (int i = 0; i < nums.length; i++) { if (value == nums[i]) { count++; } } // 返回該元素出現的次數 return count; }
結果:
優化:
這個問題最佳的解法是用到了位運算的異或操做:
5^5=0
5^7^5 = 7
5^6^6^5^7^8^7 = 8
從上面的例子能夠看出:一堆數字作異或運算^
,倆倆相同數字就會被抵消掉~,因此這個特性對於這個題目而言就再適合不過的了:
/** * 找出數組的單個數字 * @param nums * @param numsSize * @return */ public static int singleNumber(int[] nums, int numsSize) { // 第一個數和數組後面的數作^運算,留下的必然是單個數字 int k = nums[0]; for (int i = 1; i < numsSize; i++) { k = (k ^ nums[i]); } return k; }
畫三角形星星
就是要畫上面那種三角形星星,那怎麼畫呢??
思路:
實現代碼:
/** * 畫星星 */ public static void drawStar() { // 我要畫5行的星星 int row = 5; for (int i = 1; i <= 5; i++) { // 空格數等於最大行數 - 當前行數 for (int j = 1; j <= row - i; j++) { System.out.print(" "); } // 星星數等於(當前行數*2-1) for (int j = 1; j <= i * 2 - 1; j++) { System.out.print("*"); } // 每畫一行就換一次行 System.out.println(); } }
結果:
羅馬數字倒轉成阿拉伯數字
羅馬數字咱們可能在英語的題目中看得是比較多的,通常經常使用的咱們是阿拉伯數字,那怎麼轉成阿拉伯數字呢??咱們先來了解一下羅馬數字:
ps:來源360百科
規則在圖上已經說得挺明白的了,我舉幾個例子:
看了上面的例子估計咱們會手算將羅馬數字轉成阿拉伯數字了,那麼用程序怎麼寫呢???
思路是這樣的:
首先,咱們先定義羅馬數字和對應的阿拉伯數字(至關於查表)
// 定義羅馬數字 char digits[] = {'I', 'V', 'X', 'L', 'C', 'D', 'M'}; // 羅馬數字對應的阿拉伯數字 int values[] = { 1, 5, 10, 50, 100, 500, 1000};
隨後,咱們得找到羅馬數字當前的最大值,找到最大值以前就先得把羅馬數字轉成是阿拉伯數字
/** * 將羅馬數字轉成阿拉伯數字,實際上就是一個查表的過程 * * @param roman * @return */ public static int digitsToValues(char roman) { // 定義羅馬數字 char digits[] = {'I', 'V', 'X', 'L', 'C', 'D', 'M'}; // 羅馬數字對應的阿拉伯數字 int values[] = {1, 5, 10, 50, 100, 500, 1000}; for (int i = 0; i < digits.length; i++) { if (digits[i] == roman) { return values[i]; } } return 0; }
上面的方法已經能夠將羅馬數字轉成阿拉伯數字了,接下來咱們要查找出最大值了
/** * 找到當前羅馬數字最大值的角標 * * @param digits * @return */ public static int findMaxIndex(String digits, int L, int R) { // 假設第一個是最大的 int max = digitsToValues(digits.charAt(L)); int maxIndex = L; for (int i = L; i < R; i++) { // 將羅馬數字轉成是阿拉伯數字 int num = digitsToValues(digits.charAt(i)); if (max < num) { max = num; maxIndex = i; } } return maxIndex; }
找到了當前羅馬數字的最大值那要怎麼作???
因而乎,咱們能夠寫出下面的代碼:
/** * 將羅馬數字轉成阿拉伯數字 * * @param romanNumber * @param L * @param R */ public static int romanToNumber(String romanNumber, int L, int R) { // 若是隻有一個羅馬數字,那麼能夠直接返回了(遞歸出口) if (L == R) { return digitsToValues(romanNumber.charAt(L)); } else if (L > R) { // 若是L和R已經越界了,那麼說明沒有值了 return 0; } else { // 找到當前羅馬數字最大值的角標 int maxIndex = findMaxIndex(romanNumber, L, R); // 獲得最大值 int max = digitsToValues(romanNumber.charAt(maxIndex)); // 在最大值左邊的,則用最大值減去左邊的 int left = romanToNumber(romanNumber, L, maxIndex - 1); // 在最大值右邊的,則用最大值加上右邊的 int right = romanToNumber(romanNumber, maxIndex + 1, R); return max - left + right; } }
測試一下:
啤酒每罐2.3元,飲料每罐1.9元。小明買了若干啤酒和飲料,一共花了82.3元。咱們還知道他買的啤酒比飲料的數量少,請你計算他買了幾罐啤酒。
這是藍橋杯的一道題,咱們可使用暴力搜索便可解出:
/** * 啤酒與飲料題目 */ public static void beerAndDrink() { // 啤酒 for (int i = 0; i < 36; i++) { // 飲料 for (int j = 0; j < 44; j++) { // 錢恰好花光了,而且啤酒比飲料少 if (2.3 * i + j * 1.9 == 82.3 && i < j) { System.out.println("關注公衆號:Java3y--------------->啤酒買了" + i); } } } }
測試:
簡單凱撒密碼
凱撒密碼是啥?簡單來講:就是經過移位來進行加密
上面就是最簡單的凱撒密碼,將全部的字母進行移一位,實現加密
下面咱們也來玩一下吧~
左移動和右移動:
/** * 右移 */ public static int rotateRight(int ch) { if (ch >= 'A' && ch <= 'Y') { return ch + 1; } else if (ch >= 'a' && ch <= 'y') { return ch + 1; } else if (ch == 'Z') { return 'A'; } else if (ch == 'z') { return 'a'; } else { return ch; } } /** * 左移 */ public static int rotateLeft(int ch) { if (ch >= 'B' && ch <= 'Z') { return ch - 1; } else if (ch >= 'b' && ch <= 'z') { return ch - 1; } else if (ch == 'A') { return 'Z'; } else if (ch == 'a') { return 'z'; } else { return ch; } }
加密:
/** * 加密 * @param ch * @param shift * @return */ public static int encode(int ch, int shift) { // 若是沒有移動,則直接返回 if (shift == 0) { return ch; } else if (shift > 0) { // 若是shift移動的是正數,那麼就向右移動 for (int i = 0; i < shift; i++) { ch = rotateRight(ch); } return ch; } else { // 若是shift移動的是負數,那麼就向左移動 for (int i = 0; i < -shift; i++) { ch = rotateLeft(ch); } return ch; } }
測試:
String s = "HELLO WORLD"; char[] ch = new char[s.length()]; for (int i = 0; i < s.length(); i++) { ch[i] = (char) encode(s.charAt(i), 3); } System.out.println("關注公衆號:Java3y" + ch);
結果:
求一個數的最大公約數
算法:是兩個數相餘,直到餘數爲0,若是餘數不爲0,就用除數和餘數求餘
/** * 求最大公約數 * * @param num1 * @param num2 */ public static int gcd(int num1, int num2) { // 求餘數 int r = num1 % num2; // 若是餘數爲0,那麼除數就是最大公約數 if (r == 0) { return num2; } else { // 不然,則用除數和餘數來進行運算 return gcd(num2, r); } }
結果:
沒錯,你沒看錯,簡單的小算法也要總結!
其實我以爲這些比較簡單的算法是有"套路"可言的,你若是知道它的套路,你就很容易想得出來,若是你不知道它的套路,那麼極可能就不會作了(沒思路)。
積累了必定的"套路"之後,咱們就能夠根據經驗來推斷,揣摩算法題怎麼作了。
舉個很簡單的例子:
9*9
乘法表誰沒背過?好比看到2+2+2+2+2
,會了乘法(套路)之後,誰還會慢慢加上去。看見了5個2,就直接得出2*5
了若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:Java3y。爲了你們方便,剛新建了一下qq羣:742919422,你們也能夠去交流交流。謝謝支持了!但願能多介紹給其餘有須要的朋友