• 力扣算法入门刷题


    1、回文

    判断输入的整数是否是回文

    我的一般思路:

    将输入的整数转成字符串,再将这个字符串转成字符数组c,对字符数组进行遍历,如果第i个元素与第 c.length - i - 1 元素不相等,也就是通过比较首尾元素是否相同来判断是否是回文,只要有一个不相等就不是。

    1. public boolean isPalindrome(int x) {
    2. String s = String.valueOf(x);
    3. char[] c = s.toCharArray();
    4. for(int i=0;i
    5. //比较前后元素是否相同
    6. if(c[i]!=c[c.length-i-1]){
    7. return false;
    8. }
    9. }
    10. return true;
    11. }

    进阶思路

    先排除掉一定不为回文的数,比如最后一位是0且不为0,或者小于0的整数,再讨论可能为回文的情况,通过对整数除以十取余,对余数乘10,将原整数顺序颠倒,具体思路如下图

    1. public boolean isPalindrome(int x) {
    2. //先排除不为回文的数
    3. if(x < 0 || (x % 10 == 0&&x!=0)){
    4. return false;
    5. }
    6. //处理的余数 初值为0
    7. int reverNum = 0;
    8. while(x>reverNum){
    9. reverNum = reverNum * 10 + x % 10;
    10. x /= 10;
    11. }
    12. //第二种情况是当存在131这种以中间对称的数时会变成 1 和 13,所以需要做除以十取整操作
    13. return(x == reverNum || x == reverNum / 10);
    14. }

    2、最长公共前缀

    求一个字符串数组的最长公共前缀

    解题思路

    既然是比较一个字符串数组中所有字符串的公共前缀,那么可以额外封装一个方法,用来返回两个字符串之间的公共前缀,让他们进行两两比较,最终得出所有字符串的公共前缀

    1. public String longestCommonPrefix(String[] strs) {
    2. //先排除非0和为空的情况
    3. if(strs == null || strs.length == 0){
    4. return "";
    5. }
    6. //取第一个数作为初始值比较
    7. String prefix = strs[0];
    8. //取字符串数组的总长度作为循环执行次数
    9. int num = strs.length;
    10. //执行循环
    11. for(int i=1;i
    12. //调用比较两个字符串公共前缀的方法
    13. prefix = SelectMaxPro(prefix,strs[i]);
    14. if(prefix.length() == 0){
    15. //如果两个字符串的公共前缀为0说明没有公共前缀
    16. //一旦有两个字符串没有公共前缀则字符串数组也没有,就跳出for循环
    17. break;
    18. }
    19. if(prefix.length() == 0){
    20. return "";
    21. }
    22. }
    23. return prefix;
    24. }
    25. //创建查找两个字符最大公共前缀的方法
    26. public String SelectMaxPro(String str1,String str2){
    27. //创建一个变量作为索引,用来截取相同的前缀
    28. int index = 0;
    29. //找出两字符串之间最短的一个作为循环条件,防止数组越界
    30. int minLength = Math.min(str1.length(),str2.length());
    31. //index
    32. while(index < minLength && str1.charAt(index) == str2.charAt(index)){
    33. index++;
    34. }
    35. return str1.substring(0,index);
    36. }

    3、有效的括号

    这里先引入栈的创建方式

    栈是一种先入后出的数据结构(Last In First Out, LIFO)

    栈的基本实现

    1. public class StackDemo {
    2. public static void main(String[] args) {
    3. //使用链表创建栈
    4. LinkedList stack = new LinkedList<>();
    5. //向栈中添加元素
    6. //1、添加元素到栈顶
    7. stack.addFirst('d');
    8. //2、添加元素到栈底
    9. stack.addLast('v');
    10. //封装好的添加元素的方法
    11. stack.push('p'); //底层直接调用addFirst()
    12. //从栈中取数据
    13. //当栈中元素为空时使用这种方式进行取数据会抛出NoSuchElementException异常
    14. //1、取出栈顶元素并返回
    15. stack.removeFirst();
    16. //2、取出栈底元素并返回
    17. stack.removeLast();
    18. //3、封装好的方法返回栈顶元素
    19. stack.pop(); //它的底层就是调用了removeFirst()
    20. //查看栈中元素
    21. //1、查看第一个元素
    22. stack.getFirst();
    23. //2、查看最后一个元素
    24. stack.getLast();
    25. //封装好的方法返回栈顶元素
    26. stack.peek();
    27. }
    28. }

    题目

    给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

    有效字符串需满足:

        左括号必须用相同类型的右括号闭合。
        左括号必须以正确的顺序闭合。
        每个右括号都有一个对应的相同类型的左括号。

    1. public class Solution{
    2. //创建哈希表存储键值对
    3. Map map = new HashMap{{
    4. //使用此方式在创建哈希表示就对元素进行初始化
    5. put('(',')');put('{','}');put('[',']');put('?','?');
    6. }};
    7. public static boolean isValid(string s){
    8. if(s.length() % 2 == 1){
    9. return false;
    10. }
    11. //创建栈
    12. //此处对栈初始化一个元素,防止在栈空情况下出栈抛异常
    13. LinkedList stack = new LinkedList{{push('?')}}
    14. char[] chars = s.toCharArray;
    15. for(char c : chars){
    16. if(map.containsKey(c)) stack.push(c);
    17. //在此处进行了一个出栈的操作 满足条件就会出栈
    18. else if(c != map.get(stack.pop())) return false
    19. }
    20. return stack.size() == 1;
    21. }
    22. }

    此方法稍微有点难以理解的点在于他是何时进行的出栈,虽然他是进行一个判断栈顶元素是否等于当前元素,但当他执行完这个判断条件时就会将栈顶元素弹出,这里也可以这么理解:

    1. //弹出的字符
    2. char c = stack.pop()
    3. //如果c等于弹出字符对应的值就继续向后判断否则false
    4. if( c == map.get(c)){
    5. continue;
    6. }else{
    7. return false;
    8. }

    只能用于理解实际这么写会报错

    4、删除有序数组中的重复项并返回处理后的数组长度

    解决本题采用双指针运算,定义一个快慢指针,将快指针小于数组长度作为循环条件,如果快指针与快指针后一个位置的值相同,就说明两个元素值不相同,就将快指针的值赋给慢指针,使得不重复数据提到数组靠前的位置。但要注意双指针的初始位置都在第二位元素上,因为如果快指针在第一个位置会造成数组越界,慢指针在第一位如果前两个元素不相同,就会覆盖第一个元素。

    1. class Solution {
    2. public int removeDuplicates(int[] nums) {
    3. int length = nums.length;
    4. if(length == 0){
    5. return 0;
    6. }
    7. //定义快慢指针
    8. int fast = 1;
    9. int low = 1;
    10. while(fast < length){
    11. if(nums[fast] != nums[fast - 1]){
    12. nums[low] = nums[fast];
    13. low++;
    14. }
    15. fast++;
    16. }
    17. return low;
    18. }
    19. }

    5、移除元素

    给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

    对于此题可以采用基础的增强for循环实现,如果数组中的数据不等于目标值就在将这个值重新赋值给数组,否则就跳过该数据,这种方式在某种意义上也是一个双指针,只不过是Java封装好的

    1. class Solution {
    2. public int removeElement(int[] nums, int val) {
    3. int index = 0;
    4. for(int num : nums){
    5. if(num != val){
    6. //如果不相等就将原值重新放进数组并使指针后移
    7. nums[index++] = num;
    8. }
    9. }
    10. return index;
    11. }
    12. }

    当然也可以采用双指针的方式实现

    1. class Solution {
    2. public int removeElement(int[] nums, int val) {
    3. //定义左指针
    4. int left = 0;
    5. //定义右指针
    6. int right = nums.length-1;
    7. while(left <= right){
    8. if(nums[left] == val){
    9. nums[left] = nums[right];
    10. right--;
    11. }else{
    12. left++;
    13. }
    14. }
    15. return left;
    16. }
    17. }

    6、搜索插入位置  ----  二分查找

    给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

    本题采用二分查找算法,可以作为简单二分查找入门题

    二分查找: 定义两个指针,一个指向数组第一个位置,另一个指向数组最后一个位置,通过计算两个位置中心位置的值与目标数据进行对比,如果小于目标值,就将中间位置赋给左指针,否则赋给右指针,最后的结果一定是两指针位置相等

    1. class Solution {
    2. public int searchInsert(int[] nums, int target) {
    3. //定义左指针
    4. int left = 0;
    5. //定义右指针
    6. int right = nums.length;
    7. while(left <= right){
    8. //设置中间位置
    9. //这样处理的目的是防止(left+right)/2发生数据溢出异常,超出int型最大值
    10. int mid = left + (right - left) / 2;
    11. if(nums[mid] < target){
    12. //这里使用加一的原因是数组为递增数组,中间值已经小于目标值
    13. //所以可以直接跳过mid值
    14. left = mid + 1;
    15. }else{
    16. right = mid - 1;
    17. }
    18. }
    19. return left;
    20. }
    21. }

    7、加一

    给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。

    最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。

    你可以假设除了整数 0 之外,这个整数不会以零开头。

    1. class Solution {
    2. public int[] plusOne(int[] digits) {
    3. int n = digits.length;
    4. for(int i = n-1 ; i >= 0; --i){
    5. digits[i] = (digits[i] + 1) % 10;
    6. //如果最后一个数字加一个后不为0可以提前输出,不存在增加数组大小情况
    7. if(digits[i] != 0){
    8. return digits;
    9. }
    10. }
    11. //如果从循环中出来说明加一后数组始终为0 [9,9,9]
    12. digits = new int[n + 1];
    13. digits[0] = 1;
    14. return digits;
    15. }
    16. }

    8、求x的算术平方根  ----  二分查找算法

    给你一个非负整数 x ,计算并返回 x 的 算术平方根 。

    由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去

    方法一:二分查找

    由于一个数的算术平方根一定小于它本身,所以可以使用二分查找来实现

    1. class Solution {
    2. public int mySqrt(int x) {
    3. int index = -1;
    4. int left = 0;
    5. int right = x;
    6. while(left <= right){
    7. int mid = left + (right - left)/2;
    8. if(mid * mid <= x){
    9. index = mid;
    10. left = mid + 1;
    11. }else{
    12. right = mid - 1;
    13. }
    14. }
    15. return index;
    16. }
    17. }

    9、求x的算术平方根  ----  牛顿迭代算法

    将数x的两个平方根分别设为n、x/n,当求两个数的均值时发现这个中间值会比他们两个更接近平方根,所以对这两个数不断地求均值,最终就能够求得平方根的值

    1. public class SqrtX {
    2. public static void main(String[] args) {
    3. int x = 25;
    4. double sqrt = sqrt(x, x);
    5. System.out.println(sqrt);
    6. }
    7. public static double sqrt(int i,int x){
    8. //将平方根变成两数 n = x/n
    9. //取两数中间值
    10. //两数的中间值只会越来越接近目标值
    11. int mid = (i + x/i)/2;
    12. //当中间值与 其中一个数相等时 这个中间值就为目标值
    13. if (i == mid){
    14. return i;
    15. }else{
    16. return sqrt(mid,x);
    17. }
    18. }
    19. }

    10、求出素数的个数(不包括0和1)  ---- 暴力算法

    暴力算法定义:就是采用枚举类,将所有的情况列出或者其他大量运算又没有使用技巧来解决问题,它的优点是代码逻辑复杂度低,代码易读,缺点是浪费空间,代码效率低,会造成很多没有必要的运算

    1. public class primeNum {
    2. public static void main(String[] args) {
    3. //判断n以内的素数
    4. prime(10);
    5. }
    6. private static void prime(int n) {
    7. //对每个情况都进行枚举
    8. for(int i=2;i < n;i++){
    9. isPrime(i);
    10. }
    11. }
    12. private static void isPrime(int n) {
    13. //如果遍历的数大于要判断的数则不可能被整除,并且也排除被他自身整除
    14. //因此只需要找出在 2 ~ n-1之间能整除 n 的值则不是素数
    15. for(int i = 2; i < n ;i++ ){
    16. if(n % i == 0){
    17. return;
    18. }
    19. }
    20. //没有找到整除的为素数
    21. System.out.println(n + "是素数");
    22. }
    23. //方法改进
    24. private static void isPrime(int n){
    25. //对于求素数的方式可以在原有基础上进行改进
    26. //原本求 2 ~ n-1 会发现 会进行重复的判断
    27. // 例如12 = 2*6 3*4 4*3 6*2 会进行两次相同判断
    28. //可以发现当 达到的√12 * √12 时达到分界线
    29. //所以只需要讨论在 2 ~ √n 之间有没有能整除n的整数 但要包括这个根号
    30. //因为即使是分界值也只计算一次,所以不能丢
    31. //也可以不使用根号,直接使用i * i <= n 更妙
    32. for(int i = 2; i <= Math.sqrt(n);i++){
    33. if (n % i == 0){
    34. return;
    35. }
    36. }
    37. System.out.println(n + "是素数");
    38. }
    39. }

    10、求出素数的个数(不包括0和1)  ---- 埃筛法

    埃筛法:用已经筛选出来的素数去过滤所有能被这个素数整除的数,这些素数就像筛子一样去过滤自然数

    1. public class PrimeNum {
    2. public static void main(String[] args) {
    3. isPrime(10);
    4. }
    5. private static void isPrime(int n) {
    6. //将所有数初始化为false
    7. boolean[] flag = new boolean[n]; //false为素数
    8. //在2~n中查找因子
    9. for(int i=2 ; i < n ; i++){
    10. //2是素数进入if判断
    11. if(!flag[i]){
    12. System.out.println(i);
    13. //将i在n以内的所有倍数重新标记为true表示不为素数
    14. for(int j= 2*i;j
    15. flag[j] = true;
    16. }
    17. }
    18. }
    19. }
    20. }

    11、爬楼梯问题 (斐波那契数列问题) ---- 动态规划

    假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

    每次你可以爬 12 个台阶。你有多少种不同的方法可以爬到楼顶呢?

    借用官网动态图详解动态规划过程

    1. class Solution {
    2. public int climbStairs(int n) {
    3. int p = 1,q = 1,r = 2;
    4. for(int i = 1; i <= n ; i++){
    5. p = q;
    6. q = r;
    7. r = p + q;
    8. }
    9. return r;
    10. }
    11. }

  • 相关阅读:
    第五十七章 学习常用技能 - 查看Globals
    98. 验证二叉搜索树(中等 二叉搜索树 dfs)
    python中图片读取和保存以及plt.imshow()与cv2.imshow()显示图像颜色错误解决方案
    Git - 如何配置.gitignore文件?
    beego框架 golang web框架-网上花店
    如何通过自签名证书让本地环境变为 https
    电子元器件企业面临缺货涨价,SRM协同系统助力企业采购数字化智慧升级
    批处理的应用
    Python---死循环概念---while True
    centos服务器搭建安装Gitlab教程使用教程
  • 原文地址:https://blog.csdn.net/m0_56044262/article/details/127254489