Java学习Day6|算法|十道力扣算法题

1.整数反转

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。

class Solution {
    public int reverse(int x) {
        int rev = 0;
        while(x != 0){
            //Integer.MAX_VALUE代表int类型能取到的最大值,Integer.MIN_VALUE是最小值
            //一但rev大于最大值除以10,那么后面rev乘10的时候就要移除,所以要提前判断,返回0
            if(rev < Integer.MIN_VALUE / 10 || rev > Integer.MAX_VALUE / 10){
                return 0;
            }
            int digit = x % 10;
            x /= 10;
            rev = rev * 10 + digit;
        }
        return rev;
    }
}

2.回文数

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

class Solution {
    public boolean isPalindrome(int x) {
        //带有负号,肯定不是回文数
        if(x < 0){
            return false;
        }
        //后面要对x进行修改,将其数值先用save保存下来
        int save = x;
        int result = 0;
        //获得x的倒序result
        while(x != 0){
            result = result * 10 + x % 10;
            x /= 10;
        }
        //判断正序倒序是否相等
        if(result == save){
            return true;
        }
        return false;
    }
}

3.删除排序数组中的重复项

给你一个 非严格递增排列 的数组 nums ,请你原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。
考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:
● 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
● 返回 k 。

class Solution {
     public int removeDuplicates(int[] nums) {
         //可以将nums[index]看作一个新数组
         //不重复的就赋值到nums[index]中,重复的就不赋值了
        int index = 0;
         //需要把后一个数跟前一个相比,所以i从1开始
        for (int i = 1; i < nums.length; i++) {
            //找到不重复的元素,赋值到数组中
            //若nums[i]不重复,则添加到nums[index]中,并且将index索引加一
            //若nums[i]重复了,就不放进去了,无需操作
            if (nums[i] != nums[index]) {
                nums[++index] = nums[i];
            }
        }
         //index是索引,元素个数也就是数组长度应该是index+1
        return index + 1;
    }
}

4.移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

class Solution {
    public int removeElement(int[] nums, int val) {
        //定义一个cur指向最新修改的位置
        //cur从0开始,若元素不需要被删除,则加入nums[cur]中,若需要删除则不加入,
        //可以将nums[cur]看作一个新数组,只不过内存空间借用了原来的数组nums
        int cur = 0;
        for(int i = 0; i < nums.length; i++){
            //若nums[i]等于val,说明要删除,就不往数组里放了
            if(nums[i] != val){
                //nums[i]不等于val,那么就不需要移除,填入到nums[cur],并且将cur加一
                nums[cur++] = nums[i];
            }
        }
        //返回长度
        return cur;
    }
}

5.搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。

class Solution {
    public int searchInsert(int[] nums, int target) {
        //查找的时间复杂度为O(log n),容易想到二分查找
        //left为左边界,right为右边界,ans记录索引
        int left = 0, right = nums.length - 1, ans = nums.length;
        while(left <= right){
            // >> 1 其实就是除以2的意思,但是因为是对二进制数直接右移操作,能够节省计算时间
            //采用right + ((left - right) >> 1能够有效防止left+right的值过大导致溢出,我认为是一个好习惯
            int mid = right + ((left - right) >> 1);
            if(target <= nums[mid]){
                //下面这两条语句能够保证ans移动到right的右一位,即目标值不存在时应该插入的位置
                ans = mid;
                right = mid - 1;
            }else{
                left = mid + 1;
            }
        }
        return ans;
    }
}

6.最后一个单词的长度

给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。
单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。

class Solution {
    public int lengthOfLastWord(String s) {
        //最后一个单词,直接倒着来,index是s的最后一位的索引
        int index = s.length() - 1;
        //等于空格就一直移动,直到找到字母停止移动
        while(s.charAt(index) == ' '){
            index--;
        }
        int wordLength = 0;
        while(index >= 0 && s.charAt(index) != ' '){
            wordLength++;
            index--;
        }
        return wordLength;
    }
}

7.合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        //为了节省空间,不创建第三个数组,直接在nums1中排列
        //因为nums1的长度为m+n,后边是有足够的空间的,所以我们从后边开始从大到小填入nums1
        //定义p1指向nums1中接下来要比较的数值,定义p2指向nums2中接下来要比较的数值
        int p1 = m - 1, p2 = n - 1;
        //定义索引,从nums1的最末尾开始
        int index = m + n - 1;
        //p1和p2均大于等于0时,两个原本的数组都还有数据,此时要循环比较
        while(p1 >= 0 && p2 >= 0){
            //谁大索引处就放谁
            if(nums1[p1] >= nums2[p2]){
                nums1[index] = nums1[p1];
                p1--;
                index--;
            }else{
                nums1[index] = nums2[p2];
                p2--;
                index--;
            }
        }
        //当nums1中原本的数值都已经比较完了以后,p1为-1,此时直接将nums2中的所有数值按序填入
        //若此时p2也为负,则循环不会进行,程序结束
        if(p1 < 0){
            for(int i = p2; i >= 0; i--){
                nums1[i] = nums2[i];
            }
        }
        //只需要判断p1小于0,因为本次排序是直接使用的nums1,所以
        //当p2先为负时,p1就算有值,也已经按序排好在nums1中最前面的位置了
    }
}

8.验证回文串

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。
字母和数字都属于字母数字字符。
给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 。

class Solution {
    public boolean isPalindrome(String s) {
        //定义left从字符串的第一位往后遍历,right从字符串的最后一位往前遍历
        int left = 0, right = s.length() - 1;
        while(left < right){
            //取出对应索引出的字符
            char cl = s.charAt(left);
            char cr = s.charAt(right);
            //注意这里有个!
            //判断字符是否为数字或者字母,如果不是,就直接移动指针
            if(!(('0' <= cl && cl <= '9') || ('A' <= cl && cl <= 'Z') || ('a' <= cl && cl <= 'z'))){
                left++;
                continue;
            }
            if(!(('0' <= cr && cr <= '9') || ('A' <= cr && cr <= 'Z') || ('a' <= cr && cr <= 'z'))){
                right--;
                continue;
            }
            //将小写字母-32转换为大写字母,原因有二:
            //1.本题要求无视字母大小写,只要是同一个字母,不管大写还是小写都视为相同
            //2.如果直接判断传入的字符-32,那么可能会导致大写字母转换为数字,然后和数字相等的情况
            //ASCII码表中,0~9对应范围48~57,A~Z对应范围65~90
            //所以大写字母是有可能被误判成与数字相等的,比如,本来只想得到诸如'a'-32='A'这样的结果
            //但是比如把'P'-32,就会得到'0',造成大写字母与数字判定相等的情况。('P'对应80,'0'对应48)
            if('a' <= cl && cl <= 'z'){
                cl -= 32;
            }
            if('a' <= cr && cr <= 'z'){
                cr -= 32;
            }
            //这里就可以放心地直接比较两个字符是否相等了,不相等直接返回false,相等的话移动指针,继续遍历比较
            if(cl != cr){
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

9.只出现一次的数字

之前单门发过这道题的题解,并且还扩展了两道相关的题目,一共三道算法题,文章地址如下:
算法|只出现一次的数字I,II,III

10.加一

给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。

class Solution {
    public int[] plusOne(int[] digits) {
        //这个题的思路是:如果最后一位不是9,那么就可以直接给最后一位加1
        //如果最后一位是9,就要往前找,找到第一个不是9的地方,将其加1。而在此之前遍历过的9都要改为0
        //如果这个数全是9,那么就创建一个新的比digits长度大1的数组,数组首位为1,其他位置0

        //最后一位不是9,直接加1并返回数组
        if(digits[digits.length - 1] != 9){
            digits[digits.length - 1] += 1;
            return digits;
        }
        //遍历过的9都改为0,将第一个遇到的不是9的数加1,并且返回数组
        for(int i = digits.length - 1; i >= 0; i--){
            if(digits[i] == 9){
                digits[i] = 0;
            }else{
                digits[i]++;
                return digits;
            }
        }
        //能进行到这一步,说明刚才遍历整个数组都是9所以才没有返回数组
        //因为遍历的时候将9都改为了0,所以此时数组的首位元素也是0
        if(digits[0] == 0){
            //创建新数组,首位赋值为1,其余位置均为0,因为数组中默认值为0,所以其他位置就不赋值了
            int[] newDigits = new int[digits.length + 1];
            newDigits[0] = 1;
            return newDigits;
        }
        return null;
    }
}

如果对您有帮助,请点赞关注支持我,谢谢!
如有错误或者不足之处,希望您能够加以指正!

你可能感兴趣的:(不易,Java基础知识,算法,java)