顺序查找
分治算法
回溯、分治、和动态规划算法可以规划为一类,都会涉及到递归。
动态规划是一类算法问题,
动态规划
递归求x的n次方
package Temp;
import java.util.Scanner;
/*
* @Author: jun
* @Date:2023/1/30 0:03
* @概述:
*/
public class niuke004 {
//求x的n次方
static int function01(int x, int n){
int result = 1;//把结果赋值为1是为了表示所有的数的0次方都是1
for (int i = 0; i < n; i++) {//循环n次中每次的result都是取了n-1次方的结果
result = result * x;
}
return result;//返回x的n次方
}
static int recursive(int x, int n){
if (n == 0){
return 1;
}
return x*recursive(x,n-1);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
//使用普通的for循环计算x的n次方结果
System.out.println("使用普通的for循环计算x的n次方结果");
System.out.println("输入x的值:");
int x = scanner.nextInt();
System.out.println("输入n的值:");
int n = scanner.nextInt();
long start = System.nanoTime();
System.out.println("result="+function01(x,n));
long end = System.nanoTime();
System.out.println("时间消耗"+(end-start));
System.out.println("_________________");
//使用递归的算法解决该题
System.out.println("使用递归的算法解决该题");
long start02 = System.nanoTime();
System.out.println("recursive result="+recursive(x,n));
long end02 = System.nanoTime();
System.out.println("时间消耗"+(end02-start02));
}
}
有序数组的平方排列
package Temp;
/*
* @Author: jun
* @Date:2023/2/17 8:32
* @概述:
*/
public class niuke005 {
//有序数组的平方排列
static class solution{
public int[] sortSquares(int[] nums){
int right = nums.length-1;//定义右指针
int left = 0;//定义左指针
int[] result = new int[nums.length];//新建一个数组用于返回排序后结果,并且大小等于原需排列的数组
int index = result.length-1;//给新建的数组也定义一个指针,让它从最后一位开始移动,返回比较后的较大值
while(left<=right){//常规的双指针的条件就是左指针与右指针交错
//每次比较是用平方后的值来比较
if (nums[left]*nums[left] > nums[right]*nums[right]){
//将大的left添入新数组的右边,
result[index--] = nums[left]*nums[left];
++left;//将原数组比较的左指针右移,right不变
} else {
//相反的
result[index--] = nums[right]*nums[right];
--right;
}
}
return result;
}
}
public static void main(String[] args) {
int[] arr = {-1,2,3,5,8,17};
solution solution = new solution();
int[] ints = solution.sortSquares(arr);
for (int i:ints
) {
System.out.println(i);
}
}
}
前n项和的时间复杂度
package Temp;
/*
* @Author: jun
* @Date:2023/2/17 9:01
* @概述:
*/
public class temp006 {
//前n项和的时间复杂度
//1+2+3+···+100
static int solution01(int n){
int sum = 0;
while(n>0){
sum+=n;
n--;
}
return sum;
}
//设计时间复杂度为O(1)的算法
static int solution02(int n){
return n*(n+1)/2;
}
//解法三
public static void main(String[] args){
long stime = System.nanoTime();
System.out.println(solution01(100));
long etime = System.nanoTime();
long time01 = System.nanoTime();
System.out.println(solution02(100));
long time02 = System.nanoTime();
System.out.println(etime-stime);
System.out.println(time02-time01);
}
}
两个数组的交集
package Temp;
/*
* @Author: jun
* @Date:2023/2/17 13:24
* @概述:
*/
import java.util.HashSet;
/**
* 两个数组的交集
* 题意:给定两个数组,编写一个函数来计算它们的交集
*/
public class temp008 {
public static int[] intersection(int[] nums1,int[] nums2){
//首先判断这两个数组是否是空的,如果有一方是空的就直接放回一个空数组
if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0){
return new int[0];
}
//新建两个hashset
HashSet<Object> set1 = new HashSet<>();
HashSet<Object> resSet = new HashSet<>();
//遍历数组set1
for (int i:nums1) {
set1.add(i);
}
//遍历数组2的过程中判断哈希表set1中是否存在该元素
for ( int i:nums2){
if (set1.contains(i)){
resSet.add(i);
}
}
return resSet.stream().mapToInt(x -> (int) x).toArray();
}
public static void main(String[] args) {
int[] arr1 = {1,2,3,4,5,5};
int[] arr2 = {1,5};
for (int i: intersection(arr1,arr2)
) {
System.out.println(i);
}
}
}
快乐数
package Temp;
/*
* @Author: jun
* @Date:2023/2/17 13:40
* @概述:
*/
import java.util.HashSet;
import java.util.Set;
/**
* 快乐数
* 编写一个算法来判断一个数是否是快乐数
* 快乐数的定义:对于一个正整数,
* 每一次将该数替换为它每一个位置上的数字的平方和,
* 然后重复这个过程直到这个数变为一,也可能是无限循环
* 但最终变不到一,如果可以变为一,那么这个数就是快乐数。
*/
public class temp009 {
//获取每位数
static int getNextNumber(int n){
int res = 0;//返回值
while(n>0){
int temp = n%10;//取得一位数
res += temp*temp;//每位数都要进行平方求其值
n = n / 10;//相当于末尾位取出
System.out.println(temp);
}
return res;
}
public static void main(String[] args) {
getNextNumber(113);
int n = 123;
Set<Integer> record = new HashSet<>();
while(n!=1&&!record.contains(n)){
record.add(n);
n = getNextNumber(n);
}
System.out.println(n);
}
}
两数之和
package Temp;
/*
* @Author: jun
* @Date:2023/2/17 16:15
* @概述:
*/
import java.util.HashMap;
/**
* 两数之和
*
*/
public class temp010 {
static int[] twoSum(int[] nums,int target){
int[] res = new int[2];//返回值为一个两个空间大小的数组
if (nums == null || nums.length == 0){
return res;
}
HashMap<Integer, Integer> map = new HashMap<>();//新建一个哈希表,键和值都是整型
for (int i = 0; i < nums.length; i++) {
int temp = target - nums[i];//遍历当前元素,并在map中寻找是否有匹配的数
if(map.containsKey(temp)){
res[1] = i;
res[0] = map.get(temp);
break;
}
map.put(nums[i],i);//每次循环都把遍历过的数放进map
}
return res;
}
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6};
int target = 10;
int[] ints = twoSum(arr, target);
for (int i :
ints) {
System.out.println(i);
}
}
}
四数相加
package Temp;
/*
* @Author: jun
* @Date:2023/2/17 16:47
* @概述:
*/
import java.util.HashMap;
import java.util.Map;
/**
* 四数相加
* 给定四个包含整数的数组列表A,B,C,D,计算有多少个元组(i,j,k,l),
* 使A[i]+B[j]+C[k]+D[I]=0
*/
public class temp011 {
static int fourSumCount(int[] nums1,int[] nums2,int[] nums3,int[] nums4){
Map<Integer,Integer> map = new HashMap<>();
int temp;
int res = 0;
//统计两个数组中的元素之和,同时统计出现的次数,放入map
for (int i:nums1){
for (int j :
nums2) {
temp = j + i;
if (map.containsKey(temp)){
map.put(temp,map.get(temp)+1);
}else{
map.put(temp,1);
}
}
}
//统计剩余的两个元素的和,在map中找是否存在相加为0的情况,同时记录次数
for (int i :
nums3) {
for (int j :
nums4) {
temp = i + j;
if (map.containsKey(0-temp)){
res += map.get(0 - temp);
}
}
}
return res;
}
public static void main(String[] args) {
int[] arr1 = {-1,2,3,4};
int[] arr2 = {1,-2,3,4};
int[] arr3 = {1,2,-3,4};
int[] arr4 = {1,2,3,-4};
int i = fourSumCount(arr1, arr2, arr3, arr4);
System.out.println(i);//i个元组
}
}
三数之和
package Temp;
/*
* @Author: jun
* @Date:2023/2/17 17:30
* @概述:
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 三数之和
* 给定一个包含n个整数的数组nums,判断nums中是否存在三个元素a,b,c,使得a+b+c=0
* 需要找出不可以重复的三元组。
*
* 总共三个数:i,left,right
* i是nums里遍历的元素,重复了的话就直接跳过去
* 虽然不能有重复的三元组,但三元组内的元素是可以重复
*
* left与right的去重
*/
public class temp012 {
static List<List<Integer>> threeSum(int[] nums){
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);//将数组排序
//求a + b + c = 0;
//a = nums[i],b = nums[left], c = nums[right]
for (int i = 0; i < nums.length; i++) {
//排序之后如果第一个元素大于零,则说明无论如何组合都不可能三个数和为0
if (nums[i]>0){
return result;
}
if (i > 0 &&nums[i] == nums[i-1]){
continue;//去重a
}
int left = i+1;//左指针起始位置
int right = nums.length-1;//右指针至于最右侧
while(right>left){
int sum = nums[i] + nums[left] + nums[right];
if (sum>0){
right--;
}else if (sum < 0){
left++;
}else{
result.add(Arrays.asList(nums[i],nums[left],nums[right]));
//去重逻辑应该放在找到一个三元组之后,对b和c去重
while(right>left&&nums[right] == nums[right-1])right--;
while(right>left&&nums[right] == nums[left+1])left--;
right--;
left++;
}
}
}
return result;
}
public static void main(String[] args) {
int[] arr = {-1,0,1,2,-1,-4};
List<List<Integer>> lists = threeSum(arr);
System.out.println(lists);
}
}
反转字符串
package Temp;
/*
* @Author: jun
* @Date:2023/2/18 10:19
* @概述:
*/
/**
* 反转字符串
* 编写一个函数,作用是将输入的字符串反转过来,输入字符串以字符数组char[]的形式给出
* 要求是不使用额外的数组分配空间,你必须原地修改数组
*
*/
public class temp013 {
static char[] reverseString(char[] s){
int l = 0;
int r = s.length - 1;
while(l<r){
s[l] ^= s[r];//构造a^b,并放在a中
s[r] ^= s[l];//将a^b 这一结果再^b,此时b = a,a = a^b
s[l] ^= s[r];//a^b的结果再^a,存入a中,此时b = a,a=b
//完成交换后移动两个指针
l++;//左指针右移
r--;//右指针左移
}
return s;
}
public static void main(String[] args) {
char[] arr = {'A','B','C','D'};
char[] chars = reverseString(arr);
System.out.println(chars);
}
}
反转字符串II
package Temp;
/*
* @Author: jun
* @Date:2023/2/18 10:50
* @概述:
*/
/**
* 反转字符串II
* 给定一个字符串s和一个整数k,从字符串开头算起,每计数至2k个字符,就反转这2k个字符中的前k个字符
* 如果剩余字符小于k个,则将剩余字符全部反转
* 如果剩余字符小于2k但大于或等于k个,则反转前k个字符,其余字符保持原样。
*/
public class temp014 {
static String reverseStr(String s,int k){
StringBuffer res = new StringBuffer();
int length = s.length();
int start = 0;
while(start < length){
//找到每次需要反转得中点k,还有末尾2k
StringBuffer temp = new StringBuffer();//新建一个可变字符串stringBuffer
//与length进行判断,如果大于length了,那就将其置为length
int firstK = (start + k >length)?length : start+k;
int secondK = (start + (2*k)>length)?length : start +(2*k);
//无论start所处的位置,至少会反转一次
temp.append(s.substring(start,firstK));//获取从start到firstK的字符
res.append(temp.reverse());//使用stringBuffer自带的反转方法反转
//如果firstK到secondK之间有元素,这些元素直接放入res里即可
if (firstK < secondK){
res.append(s.substring(firstK,secondK));
}
start += (2*k);//当length足够时,更改start的位置为2k
}
return res.toString();
}
public static void main(String[] args) {
int target = 6;
String chars = "adadsfdsvfbsbsrtgbr";
String s = reverseStr(chars, target);
System.out.println(s);
}
}
替换空格
package Temp;
/*
* @Author: jun
* @Date:2023/2/18 11:58
* @概述:
*/
/**
* 替换空格
* 实现一个函数,把字符串s中的每一个空格替换为"%20"
* 示例:输入: s = "We are happy"
* 输出:"We%20are%20happy"
*
*/
public class temp015 {
/**
* 思路:方法有很多,这里我们考虑优质的算法
* 首先扩充数组到每个空格替换成”%20“之后的大小
* 然后从后向前替换空格,就是双指针法,
* 这里为什么要从后向前填充?,为什么不是从前向后填充?
* 从前向后填充是O(n^2)的算法,每次操作都要将添加元素之后的所有元素向后移动
*
*/
static String replaceSpace(String s){
if (s == null){
return null;
}
//选用StringBuilder单线程使用,比较快
StringBuilder stringBuilder = new StringBuilder();
//使用stringBuilder逐个复制,碰到空格就替换掉,否则直接复制
for (int i = 0; i < s.length(); i++) {
//s.charAt(i)为了char类型,为了比较需要将其转为和" "相同的字符串类型
//if(" ".equals(String.valueOf(s.charAt(i)))){}
if (s.charAt(i) == ' ') {
stringBuilder.append("%20");
} else {
stringBuilder.append(s.charAt(i));
}
}
return stringBuilder.toString();
}
public static void main(String[] args) {
String s = "We are happy";
String s1 = replaceSpace(s);
System.out.println(s1);
}
}
翻转字符串中的单词
package Temp;
/*
* @Author: jun
* @Date:2023/2/18 13:55
* @概述:
*/
/**
*翻转字符串中的单词
* 给定一个字符串,逐个翻转字符串中的每个单词
* 示例:
* 输入: "the sky is blue"
* 输出: "blue is sky the"
*/
public class temp016 {
/**
* 思路:
* 提高题目难度:不能用辅助空间,空间复杂度为O(1)
* 不能使用辅助空间的话就只能在原字符串上下功夫
* 主要有以下几步思路:
* 1.移除多余空格
* 2.将整个字符串反转
* 3.将每个单词反转
* 举个例子,源字符串为:"the sky is blue "
*
* 移除多余空格 : "the sky is blue"
* 字符串反转:"eulb si yks eht"
* 单词反转:"blue is sky the"
*/
public String reverseWords(String s){
//1.去除首尾以及中间多余的空格
StringBuilder sb = removeSpace(s);
//2.反转整个字符串
reverseString(sb,0,sb.length()-1);
//3.反转各个单词
reverseEachWord(sb);
return sb.toString();
}
//去除空格
private StringBuilder removeSpace(String s){
int start = 0;
int end = s.length() - 1;
while(s.charAt(start) == ' ')start++;
while(s.charAt(end) == ' ')end--;
StringBuilder stringBuilder = new StringBuilder();
while(start <= end){
char c = s.charAt(start);
if (c != ' ' || stringBuilder.charAt(stringBuilder.length() - 1)!= ' '){
stringBuilder.append(c);
}
start++;
}
return stringBuilder;
}
/**
* 反转字符串指定区间[start, end]的字符
*/
public void reverseString(StringBuilder sb, int start, int end) {
// System.out.println("ReverseWords.reverseString() called with: sb = [" + sb + "], start = [" + start + "], end = [" + end + "]");
while (start < end) {
char temp = sb.charAt(start);
sb.setCharAt(start, sb.charAt(end));
sb.setCharAt(end, temp);
start++;
end--;
}
// System.out.println("ReverseWords.reverseString returned: sb = [" + sb + "]");
}
private void reverseEachWord(StringBuilder sb) {
int start = 0;
int end = 1;
int n = sb.length();
while (start < n) {//
while (end < n && sb.charAt(end) != ' ') {
end++;
}
reverseString(sb, start, end - 1);
start = end + 1;
end = start + 1;
}
}
public static void main(String[] args) {
temp016 temp016 = new temp016();
String s = "the sky is blue";
String s1 = temp016.reverseWords(s);
System.out.println(s1);
}
}
左旋转字符串
package Temp;
/*
* @Author: jun
* @Date:2023/2/18 15:21
* @概述:
*/
/**
*左旋转字符串
* 字符串的左旋转操作是把字符串前面的诺干个字符转移到字符串的尾部,请定义一个函数实现字符串左旋转操作的功能。
* 示例 1:
* 输入: s = "abcdefg", k = 2
* 输出: "cdefgab"
*
* 示例 2:
* 输入: s = "lrloseumgh", k = 6
* 输出: "umghlrlose"
*/
public class temp017 {
/**
* 解题思路:
* 用原始的数组来进行反转操作
* 先将整个字符串反转,再反转前面的字符串,最后反转后面的n个
*
*/
public String reverseLeftWords(String s,int n){
char[] chars = s.toCharArray();//将s转化为chars字符数组
//整个字符串反转
reverse(chars,0,chars.length-1);
//前n个反转
reverse(chars,0,chars.length-1-n);
//后n到length-1反转
reverse(chars,chars.length-n,chars.length-1);
return new String(chars);
}
public void reverse(char[] chars,int left,int right){
while(left < right){
chars[left] ^= chars[right];
chars[right] ^= chars[left];
chars[left] ^= chars[right];
left++;
right--;
}
}
public static void main(String[] args) {
temp017 temp017 = new temp017();
String s = "abcdefg";
String s1 = temp017.reverseLeftWords(s,2);
System.out.println(s1);
}
}
移除元素
package Temp;
/*
* @Author: jun
* @Date:2023/2/20 10:14
* @概述:
*/
/**
* 移除元素
*
* 给定一个数组nums和一个值val,你需要原地移除所有数值等于val的元素,并返回移除数组的新长度
* 不要使用额外的数组空间,你必须使用O(1)额外空间并原地修改输入数组
* 元素的顺序可以改变,你不需要考虑数组中超过新长度后面的元素
*/
public class temp018 {
/**
*示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。
*
* 示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
*/
//使用快慢指针
public int removeElement(int[] nums,int val){
//慢指针
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
if (nums[fastIndex] != val){
nums[slowIndex] = nums[fastIndex];//慢指针的位置值变为快指针的值,相当于慢指针所走过的就是一个新的数组,在原数组基础上
slowIndex++;
}
}
return slowIndex;
}
public static void main(String[] args) {
int[] arr = {1,2,2,3,4,5,2,4};
temp018 temp018 = new temp018();
int i = temp018.removeElement(arr, 2);
System.out.println(i);
}
}
有效的括号
package Temp;
/*
* @Author: jun
* @Date:2023/2/20 11:03
* @概述:
*/
import java.util.Deque;
import java.util.LinkedList;
/**
* 有效的括号
*
*/
public class temp020 {
/**
* 什么时候开始匹配?当一个完全匹配类型开始匹配就是出栈的时候
* 在一次栈顶时,会有元素开始成功出栈,(出栈的条件是有对应的括号刚好匹配
*
* 什么时候匹配结束?当栈为空,没有元素需要入栈就已经匹配完成
*
*
*/
//返回类型为布尔类型
public boolean isValid(String s){
//新建一个栈
Deque<Character> deque = new LinkedList<>();
char ch;
for (int i = 0; i < s.length(); i++) {
ch = s.charAt(i);
//碰到左括号就把相应的右括号入栈
if (ch == '('){
deque.push(')');
}else if (ch == '{'){
deque.push('}');
}else if (ch == '['){
deque.push(']');
}else if (deque.isEmpty()||deque.peek() != ch){
return false;
}else{
deque.pop();
}
}
return deque.isEmpty();//最后判断栈中元素是否匹配
}
public static void main(String[] args) {
String s = "(){}()[]{()}";
temp020 temp020 = new temp020();
boolean valid = temp020.isValid(s);
System.out.println(valid);
}
}
删除字符串中的所有相邻重复项
package Temp;
/*
* @Author: jun
* @Date:2023/2/20 13:03
* @概述:
*/
/**
* 删除字符串中的所有相邻重复项
* 输入:"abbaca"
* 输出:"ca"
* 解释:例如,在 "abbaca" 中,
* 我们可以删除 "bb" 由于两字母相邻且相同,
* 这是此时唯一可以执行删除操作的重复项。
* 之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,
* 所以最后的字符串为 "ca"。
*/
public class temp021 {
//ArrayDeque会比LinkedList在除了删除元素这一点外会快一点
//使用双指针算法求解,这种方法较为抽象,可以用更简单的
public String removeDuplicates(String s){
char[] chars = s.toCharArray();//将字符串转化为字符数组
int fast = 0;
int slow = 0;
while(fast < s.length()){
//直接用fast指针覆盖slow指针的值
chars[slow] = chars[fast];
//遇到前后相同值的,就跳过,即slow指针后退一步,下次循环就可以直接被覆盖掉了
if (slow > 0 && chars[slow] == chars[slow-1]){
slow -- ;
}else{
slow ++ ;
}
fast ++ ;
}
return new String(chars,0,slow);//返回一个新的字符串String
}
/**
* 使用字符串作为栈,省去了栈还要转为字符串的操作
*/
public String remove02(String s){
//将res作为栈
//也可以用StringBuilder来修改字符串,速度更快
//写法为 StringBuilder res = new StringBuilder();
StringBuffer res = new StringBuffer();
//初始化top为res的长度
int top = -1;
for (int i = 0; i < s.length(); i++) {
//将s的字符逐个提取出来
char c = s.charAt(i);
if (top >= 0 && res.charAt(top) == c){//一开始利用top<0给StringBuffer添加元素
res.deleteCharAt(top);
top--;
}else{
res.append(c);
top++;
}
}
return res.toString();//将res返回出来并转化为字符串
}
public static void main(String[] args) {
String s = "abbaca";
temp021 temp021 = new temp021();
String s1 = temp021.removeDuplicates(s);
System.out.println(s1);
String s2 = temp021.remove02(s);
System.out.println(s2);
}
}
逆波兰表达式
package Temp;
/*
* @Author: jun
* @Date:2023/2/20 15:15
* @概述:
*/
import java.util.LinkedList;
/**
* 逆波兰表达式求值
* 根据逆波兰表达式,求表达式的值
* 有效的运算符包括 + - * / 每个运算对象都可以是整数,也可以是另一个逆波兰表达式
*/
public class temp022 {
public int evalRPN(String[] tokens){
LinkedList<Integer> stack = new LinkedList();
for (String s :
tokens) {
if ("+".equals(s)){
stack.push(stack.pop()+stack.pop());//相当于遇到了当前这个符号就将栈顶的两个元素push然后运算
}else if ("-".equals(s)){
stack.push(-stack.pop()+stack.pop());
}else if ("*".equals(s)){
stack.push(stack.pop()*stack.pop());
}else if ("/".equals(s)){
int temp1 = stack.pop();
int temp2 = stack.pop();
stack.push(temp2/temp1);
}else{
stack.push(Integer.valueOf(s));
}
}
return stack.pop();
}
public static void main(String[] args) {
String[] s = {"2","1","+","3","*"};
temp022 temp022 = new temp022();
int i = temp022.evalRPN(s);
System.out.println(i);
}
}