前言
最近在回顧以前使用C寫過的資料結構和演算法的東西,發現自己的演算法和資料結構是真的薄弱,現在用Java改寫一下,重溫一下。
只能說慢慢積累吧~下面的題目難度都是簡單的,演算法的大佬可直接忽略這篇文章了~入門或者演算法薄弱的同學可參考一下~
很多與排序相關的小演算法(合併陣列、獲取數字每位值的和),我都沒有寫下來了,因為只要會了歸併排序(合併陣列),會了桶排序(獲取數字每位的值),這些都不成問題了。如果還不太熟悉八大基礎排序的同學可看:【八大基礎排序總結】
由於篇幅問題,每篇寫十道吧~
如果有錯的地方,或者有更好的實現,更恰當的理解方式希望大家不吝在評論區留言哦~大家多多交流
十道簡單演算法題
題目的總覽
1-n
階乘之和- 獲取二維陣列每列最小的值
- 求"1!+4!(2的平方)+9!(3的平方)+...+n的值
- 陣列對角線元素之和
- 列印楊輝三角形
- 猴子吃桃子問題
- 計算單詞的個數
- 判斷字母是否完全一樣
- 判斷一個數是不是2的某次方
- 判斷一個數字是不是ugly number
一、1-n階乘之和
1-n階乘之和怎麼算?
- 1的階乘是
1
- 2的階乘是
1*2
- 3的階乘是
1*2*3
- 4的階乘是
1*2*3*4
- .........
現在我們要求這些階乘的和。思路:
- 3階乘的和其實上就是2階乘的和+3的階乘
- 4階乘的和其實上就是3階乘的和+4的階乘
- .......
/**
* 1-n的階乘之和
*/
public static void Factorial(int n) {
//總和
double sum = 0;
//階乘值,初始化為1
double factorial = 1;
for (int i = 1; i <= n; i++) {
factorial = factorial * i;
sum = (int) (sum + factorial);
}
System.out.println("公眾號:Java3y" + " " + sum);
}
複製程式碼
二、獲取二維陣列每列最小的值
獲取二維陣列每列最小的值
思路:遍歷列,再遍歷列中行
我們一般運算元組都是從行開始,再到列的。這次要求的是每列的最小值,因此需要在內部for迴圈遍歷的是行
/**
* 求出二維陣列每列的最小值
*/
public static void minArray() {
//二維陣列
int[][] arrays = {
{23, 106, 8, 234},
{25, 9, 73, 19},
{56, 25, 67, 137}
};
//獲取列數
int maxColLength = arrays[0].length;
//使用一個陣列來裝載每列最小的值
int[] minArray = new int[maxColLength];
//控制列數
for (int i = 0; i < maxColLength; i++) {
//假設每列的第一個元素是最小的
int min = arrays[0][i];
//控制行數
for (int j = 1; j < arrays.length; j++) {
//找到最小值
if (arrays[j][i] < min) {
min = arrays[j][i];
}
}
//賦值給裝載每列最小的值的陣列
minArray[i] = min;
}
System.out.println("公眾號:Java3y" + " " + minArray);
}
複製程式碼
三、求"1!+4!(2的平方)+9!(3的平方)+...+n的值
求"1!+4!(2的平方)+9!(3的平方)的值
思路:先求平方,後求階乘,最後相加即可~
/**
* 求"1!+4!(2的平方)+9!(3的平方)+...+n的值
*/
public static void calculate() {
double sum = 0;
for (int i = 1; i <= 3; i++) {
//得到平方數
int square = i * i;
//階乘值,從1開始
double factorial = 1;
//求階乘
for (int j = 1; j <= square; j++) {
factorial = factorial * j;
}
sum = sum + factorial;
}
System.out.println("公眾號:Java3y" + " " + sum);
}
複製程式碼
四、陣列對角線元素之和
陣列對角線元素之和
思路:
- 只要行和列相等,即是對角線的元素
/**
* 陣列對角線之和
*/
public static void arraySum() {
int[][] arrays = {
{23, 106, 8, 234},
{25, 9, 73, 19},
{56, 25, 67, 137},
{33, 22, 11, 44},
};
//和
int sum = 0;
for (int i = 0; i < arrays.length; i++) {
for (int j = 0; j < arrays[i].length; j++) {
if (i == j) {
sum = sum + arrays[i][j];
}
}
}
System.out.println("公眾號:Java3y" + sum);
}
複製程式碼
五、列印楊輝三角形
楊輝三角形
楊輝三角形長的是這個樣子:
ps:圖片來源網上,侵刪~
規律:
- 每行的第一個和最後一個都是1
- 進一步推算:第1列全部為1,第一行全都是1,當列數等於行數為1
- 當前值等於頭上的值加頭上的左邊的值
- 第一行一列,第二行兩列,第三行三列.......
程式碼實現:
/**
* 列印楊輝三角形
*/
public static void PascalTriangle() {
//列印十行的楊輝三角形
int[][] arrays = new int[10][];
//行數
for (int i = 0; i < arrays.length; i++) {
//初始化第二層的大小
arrays[i] = new int[i + 1];
//列數
for (int j = 0; j <= i; j++) {
//是第一列,第一行,行數等於列數,那麼通通為1
if (i == 0 || j == 0 || j == i) {
arrays[i][j] = 1;
} else {
//當前值等於頭上的值+頭上左邊的值
arrays[i][j] = arrays[i - 1][j] + arrays[i - 1][j - 1];
}
}
}
System.out.println("公眾號:Java3y" + "-------------------------------");
for (int[] array : arrays) {
for (int value : array) {
System.out.print(value + "\t");
}
System.out.println();
}
System.out.println("公眾號:Java3y" + "-------------------------------");
}
複製程式碼
結果:
六、猴子吃桃子問題
猴子摘下了n個桃子,當天吃掉一半多一個,第二天也是吃掉剩下桃子的一半多一個,到了第十天,桃子只剩下了1個。問:猴子第一天摘了多少個桃子
思路:
- 假設當天有n個桃子,它是前一天桃子的一半少1個,
f(n - 1) = f(n)/2 - 1
, - 我們就可以推出當天桃子的個數:根據遞推公式:
f(n) = 2 * f(n - 1) + 2
用遞迴和迴圈都可解決:
遞迴方式:
/**
* 猴子吃桃問題
* @param x 天數
*/
public static int monkeyQue(int x) {
if (x <= 0) {
return 0;
} else if (x == 1) {
return 1;
} else {
return 2 * monkeyQue(x - 1) + 2;
}
}
複製程式碼
迴圈方式:
int x = 1;
for (int i = 1; i <= 9; i++) {
x = (x + 1) * 2;
}
複製程式碼
結果:
七、計算單詞的個數
輸入一段字元,計算出裡面單詞的個數,單詞之間用空格隔開 ,一個空格隔開,就代表著一個單詞了
思路:
- 把字元遍歷一遍,累計由空格串轉換為非空格串的次數,次數就是單詞的個數
- 定義一個標誌性變數flag,0表示的是空格狀態,1表示的是非空格狀態
/**
* 輸入一段字元,計算出裡面單詞的個數
*
* @param str 一段文字
*/
public static int countWord(String str) {
// 0 表示空格狀態,1 表示非空格狀態
int flag = 0;
// 單詞次數
int num = 0;
for (int i = 0; i < str.length(); i++) {
if (String.valueOf(str.charAt(i)).equals(" ") ) {
flag = 0;
} else if (flag == 0) {
num++;
flag = 1;
}
}
return num ;
}
複製程式碼
結果:
八、判斷字母是否完全一樣
給定兩個字串s和t,判斷這兩個字串中的字母是不是完全一樣(順序可以不一樣)
思路:
- 遍歷這兩個字串,用每個字元減去
'a'
,將其分別存入到陣列中去,隨後看這兩個陣列是否相等即可
要點:
'c'-'a'=2
即可計算出儲存的位置,如果有多個,則+1即可,後面我們來比較陣列大小
程式碼實現:
/**
* 給定兩個字串s和t,判斷這兩個字串中的字母是不是完全一樣(順序可以不一樣)
*/
public static void isAnagram() {
//分別儲存字串的字元
char[] array1 = new char[26];
char[] array2 = new char[26];
String s1 = "pleasefollowthewechatpublicnumber";
String s2 = "pleowcnumberthewechatpubliasefoll";
for (int i = 0; i < s1.length(); i++) {
char value = s1.charAt(i);
// 算出要儲存的位置
int index = value - 'a';
array1[index]++;
}
for (int i = 0; i < s2.length(); i++) {
char value = s2.charAt(i);
// 算出要儲存的位置
int index = value - 'a';
array2[index]++;
}
for (int i = 0; i < 26; i++) {
if (array1[i] != array2[i]) {
System.out.println("不相同");
return;
}
}
System.out.println("相同");
}
複製程式碼
結果:
九、判斷一個數是不是2的某次方
判斷一個數是不是2的某次方
思路:
- 除2取餘數,直至餘數不為0【針對2的倍數這種情況】,看是不是等於1就可以判斷是不是2的某次方了
/**
* 判斷是否是2的某次方
*/
public static void isPowerOfTwo() {
int num = 3;
if (num == 0) {
System.out.println("不是");
}
while (num % 2 == 0) {
num = num / 2;
}
if (num == 1) {
System.out.println("是");
} else {
System.out.println("不是");
}
}
複製程式碼
結果:
這題還有另一種解決方式,就是位運算:
- 2的n次方都有一個特點,二進位制都是1000000
- 如果 **2的n次方的二進位制-1和2的n次方二進位制做按位與運算,那麼得出的結果肯定是0 **
if(num <= 0){
System.out.println("不是");
}
else if(num == 1){
System.out.println("是");
}
else{
if( (num & (num-1) ) == 0){
System.out.println("是");
}
else{
System.out.println("不是");
}
}
複製程式碼
十、判斷一個數字是不是ugly number
判斷一個數字是不是ugly number(分解出來的質因數只有2、3、5這3個數字)
思路:
- 如果是由2,3,5組成的,那麼這個數不斷除以2,3,5,最後得出的是1,這個數就是純粹用2,3,5組成的
- 跟之前判斷該數是否2的某次方是一樣的思路~
程式碼:
/**
* 判斷一個數字是不是ugly number(分解出來的質因數只有2、3、5這3個數字)
* @param num
*/
public static void isUgly(int num) {
if (num <= 0) {
System.out.println("不是");
} else {
while (num % 2 == 0) {
num = num / 2;
}
while (num % 3 == 0) {
num = num / 3;
}
while (num % 5 == 0) {
num = num / 5;
}
if (num == 1) {
System.out.println("是");
} else {
System.out.println("是");
}
}
}
複製程式碼
結果:
總結
沒錯,你沒看錯,簡單的小演算法也要總結!
其實我覺得這些比較簡單的演算法是有"套路"可言的,你如果知道它的套路,你就很容易想得出來,如果你不知道它的套路,那麼很可能就不會做了(沒思路)。
積累了一定的"套路"以後,我們就可以根據經驗來推斷,揣摩演算法題怎麼做了。
舉個很簡單的例子:
- 乘法是在加法的基礎之上的,那乘法我們是怎麼學的?**背(積累)**出來的,
9*9
乘法表誰沒背過?比如看到2+2+2+2+2
,會了乘法(套路)以後,誰還會慢慢加上去。看見了5個2,就直接得出2*5
了
1-n
階乘之和- 求n的階乘就用
1*2*3*4*...n
,實際上就是一個迴圈的過程,求和就套個sum變數即可!
- 求n的階乘就用
- 獲取二維陣列每列最小的值
- 外層迴圈控制列數,內層迴圈控制行數,這就是遍歷每列的方法~
- 求"1!+4!(2的平方)+9!(3的平方)+...+n的值
- 先求平方,再求階乘,最後套個sum變數
- 陣列對角線元素之和
- 行和列的位置相等,即是對角線上的元素
- 列印楊輝三角形
- 找出楊輝三角形的規律:第一行、第一列和列值等於行值時上的元素都是1,其餘的都是頭上的值加頭上的左邊的值
- 猴子吃桃子問題
- 根據條件,我們可以推算出前一天桃子,進而推出當天桃子(規律)。猴子都是在相等的條件(剩下桃子的一半多一個),因此就應該想到迴圈或者遞迴
- 計算單詞的個數
- 利用每個單詞間會有個空格的規律,用變數來記住這個狀態(字母與空格)的轉換,即可計算出單詞的個數!
- 判斷字母是否完全一樣
- 將每個字母都分別裝載到陣列裡面去,
'c-a'
就是字母c
在陣列的位置了(也就是2)。由於字母出現的次數不唯一,因此我們比較的是陣列的值(如果出現了兩次,那麼值為2,如果出現了3次,那麼值為3)。只要用於裝載兩個陣列的值都吻合,那麼字母就是一樣!
- 將每個字母都分別裝載到陣列裡面去,
- 判斷一個數是不是2的某次方
- 最佳方案:2的某次方在二進位制都有個特點:10000(n個0)--->ps:程式設計師的整數~..........那麼比這個數少一位的二進位制肯定是01111,它倆做
&
運算,那麼肯定為0。用這個特性就非常好判斷該數是否是2的某次方了 - 次方案:2的某次方的數不斷縮小(只要
number % 2 == 0
就可以縮小,每次number / 2
),最後的商必然是1。
- 最佳方案:2的某次方在二進位制都有個特點:10000(n個0)--->ps:程式設計師的整數~..........那麼比這個數少一位的二進位制肯定是01111,它倆做
- 判斷一個數字是不是ugly number
- 分解出來的質因數只有2、3、5這3個數字,這題其實就是判斷該數是否為2的某次方的升級版。將這個數不斷縮小(只要
number%2||%3||%5==0
,每次number / 2 | / 3 /5
),最後的商必然是1。
- 分解出來的質因數只有2、3、5這3個數字,這題其實就是判斷該數是否為2的某次方的升級版。將這個數不斷縮小(只要
如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同學,可以關注微信公眾號:Java3y