0
点赞
收藏
分享

微信扫一扫

leetCode进阶算法题+解析(五)

19年的最后一个工作日,整个公司请假的请假,不来的不来,出差的出差,就剩几个人在,而且还没什么工作任务,心浮气躁加上困的懵逼,,啧啧啧,先刷低保三道题。

在排序数组中查找元素的第一个和最后一个位置

题目:给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。你的算法时间复杂度必须是 O(log n) 级别。如果数组中不存在目标值,返回 [-1, -1]。

思路:这道题难点又在时间复杂度。如昨天那道一样可以用二分法。但是找到给定target之后呢?左右遍历判断第一个和最后一个位置?这样还算是logn的时间复杂度了么?
好了,就是这个思路,然后我在群里讨论了下,所谓的O(log n)应该是平均。如果真的从头到尾都是target那也是命。就酱。我直接贴代码:

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int mid = 0;
        int l = 0;
        int r = nums.length-1;
        while(l<=r){
            mid = (l+r)/2;
            if(nums[mid]>target){
                r = mid-1;
            }else if(nums[mid]<target){
                l = mid+1;
            }else{
                break;
            }
        };
        if(l>r) return new int[]{-1,-1};
        int left = mid-1;
        int right = mid+1;
        while(left>=0 && nums[left]==target){
            left--;
        }
        while(right<nums.length && nums[right]==target){
            right++;
        }
        return new int[]{left+1,right-1};
    }
}

有效的数独

题目:判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

说明:

一个有效的数独(部分已被填充)不一定是可解的。
只需要根据以上规则,验证已经填入的数字是否有效即可。
给定数独序列只包含数字 1-9 和字符 '.' 。
给定数独永远是 9x9 形式的。

思路:其实这道题挺简单的我感觉。分三步:首先这是一个99格子。第一步每一横排有没有重复元素。有的false。第二步每一竖排有没有重复元素,有false,第三步每个%3=0,1,2的33块有没有重复元素,有则false。都没有就true。我去代码实现了。**
emmmmm.....我用一种很傻的方式实现了,其实这道题来说是很简单的题目。毕竟99格子,单纯常量计算也是可以的。但是一时脑抽,觉得应该不能把代码写的那么死,所以没常量直接计算33小格子,而是代码实现的。所以写的比较复杂,四层循环解决(不要说什么设计规范不能超过3层for循环)。但是没想到代码性能还挺好。超过百分之九十六的人。所以直接贴代码了:

class Solution {
    public boolean isValidSudoku(char[][] board) {
        for(int i = 0;i<9;i++ ){
            int[] r = new int[10];
            int[] l = new int[10];
            for(int j = 0;j<9;j++){
                int n = board[i][j]-'0';
                if(n>0){
                    r[n]++;
                    if(r[n]>1){
                        return false;
                    }
                }               
                int n1 = board[j][i]-'0';
                if(n1>0){
                    l[n1]++;
                    if(l[n1]>1){
                        return false;
                    }
                }                
            } 
        }
        return isSuDoKu(board);
        
    }
    public boolean isSuDoKu(char[][] board){

        for(int i = 0;i<9;i=i+3){
            for(int j = 0;j<9;j=j+3){
                int[] r = new int[10];
                for(int k = i;k<i+3;k++){
                    for(int q = j;q<j+3;q++){
                        int n = board[k][q]-'0';
                        if(n>0){
                            r[n]++;
                            if(r[n]>1){
                                return false;
                            }
                        }                        
                    }
                }
            }
        }
        return true;

    }
}

主方法判断横竖有没有重复元素,下面的方法提出来判断3*3小格子有没有重复元素。整个方法就是来回来去循环。然后这道题因为自己做及格了所以我就不看题解了,直接下一题。

字符串相乘

题目:给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

思路:做之前说两句题外话,我现在在火车上,用笔记本艰难的刷题中,然后这次没按照顺序刷,中间呦两道数组和的题要用到回溯算法和动态规划啥的,所以暂时跳过。现在这个情况也确实静不下心来一点点抽丝剥茧。看了这个题觉得不难所以先做这道。咱们继续说思路,首先这个题说不能字符串直接转整数。这个直接有点意思,是不是不直接转就ok了?我现在的思路是转化成char,然后其中一个第一位开始往后取值(因为除了0剩下的不能是0,所以除了第一个是0剩下的直接在另一个数后面补0就行了。)然后字符会往前一个字符进位。差不多思路就是这样,接下来我去代码实现了。
刚刚的思路是对的,这道题一次通过,性能超过百分之九十六:

class Solution {
    public String multiply(String num1, String num2) {
        char[] a = num1.toCharArray();
        char[] b = num2.toCharArray();
        int al = a.length-1;
        int bl = b.length-1;
        if(al<0 || bl<0) return "";
        if(a[0]=='0' || b[0]=='0')  return "0";
        //这里加2是因为al和bl都是最后的下标而不是长度
        int[] d = new int[al+bl+2];
        for(int i = al;i>=0;i--){
            for(int j = bl;j>=0;j--){
                int n =  (a[i]-'0')*(b[j]-'0');
                n += d[i+j+1];
                d[i+j] += n/10;
                d[i+j+1] = n%10;
            }
        }
        StringBuffer sb = new StringBuffer();
        int i = 0;
        if(d[0]==0) i++;
        while(i<d.length){
           sb.append(d[i]);
           i++;
        }
        return sb.toString();
    }
}

其实这个题不难,挨个乘就行了。然后每一位的位数是累加,最后一位的是取余。就是进位问题。然后因为这个题一次过了所以就这样,直接下一题了。

图像旋转

题目:给定一个 n × n 的二维矩阵表示一个图像。将图像顺时针旋转 90 度。说明:你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。

思路:这个题其实实现很简单,但是在原数组中实现就有点难了。现在有一个大胆的想法。其实这个旋转的规律就是外框四个边往右转一下,然后里圈如果能凑出四个边继续旋转。如果凑不出来四个边说明只有一个点,就不用动了,我去照着这个思路去实现下。
思路很对,性能百分百,jiushi调试的时候一直出问题。也算是学到一招。就是因为这个是在数组的基础上改动,如果我中间改什么东西虽然会自动跳回代码的第一行,但是数组改动是不复原的。所以调试要改动一点重新debug启动。
然后继续说代码。就是一圈一圈的改动。首先一圈中四个顶点是特殊的。提出来改动。其次每个非顶点元素改动。最后一圈改动完了左右边++--。到里圈,里圈如果只有一个点不用动,超过一个点跟之前外圈一样改动。我直接贴代码了:

class Solution {
    public void rotate(int[][] matrix) {
        if(matrix.length<2) return;
        //边长大于2才有旋转的可能
        int l = 0;
        int r = matrix.length-1;
        while(l<r){//l=r 的时候说明剩一个元素,不用转了
            //四角旋转
            int temp = matrix[l][l];
            int temp1 = matrix[l][r];
            int temp2 = matrix[r][r];
            int temp3 = matrix[r][l];
            matrix[l][l] = temp3;
            matrix[l][r] = temp;
            matrix[r][r] = temp1;
            matrix[r][l] = temp2;
            for(int i = l+1;i<r;i++){
               int c1 = matrix[l][i];
               int c2 = matrix[i][r];
               int c3 = matrix[r][matrix.length-1-i];
               int c4 = matrix[matrix.length-1-i][l];
               matrix[l][i] = c4;
               matrix[i][r] = c1;
               matrix[r][matrix.length-1-i] = c2;
               matrix[matrix.length-1-i][l] = c3;
            }
            l++;
            r--;
        }  
    }
}

性能超过百分百,所以不看题解了,这篇文章写了三天,就到这吧。
如果稍微帮到你了记得点个喜欢点个关注,也祝大家工作顺顺利利!

举报

相关推荐

0 条评论