清明不当心就拖了两天没更了~~java
这是十道算法题的第二篇了~上一篇回顾:十道简单算法题git
最近在回顾之前使用C写过的数据结构和算法的东西,发现本身的算法和数据结构是真的薄弱,如今用Java改写一下,重温一下。算法
只能说慢慢积累吧~下面的题目难度都是简单的,算法的大佬可直接忽略这篇文章了~入门或者算法薄弱的同窗可参考一下~数组
不少与排序相关的小算法(合并数组、获取数字每位值的和),我都没有写下来了,由于只要会了归并排序(合并数组),会了桶排序(获取数字每位的值),这些都不成问题了。若是还不太熟悉八大基础排序的同窗可看:【八大基础排序总结】微信
因为篇幅问题,每篇写十道吧~数据结构
若是有错的地方,或者有更好的实现,更恰当的理解方式但愿你们不吝在评论区留言哦~你们多多交流dom
删除下标为k的元素数据结构和算法
思路:数组后一位往前覆盖便可~post
/** * 删除下标为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
了文章的目录导航:zhongfucheng.bitcron.com/post/shou-j…
若是文章有错的地方欢迎指正,你们互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同窗,能够关注微信公众号:Java3y