数组类总结

135. 分发糖果

注意:本题的核心就是拆解为子问题,然后使用数组的正向遍历和反向遍历特性,进行迭代求解最优解。

class Solution {
    public int candy(int[] ratings) {
        /**
        分析:
        每个孩子至少分配1个糖果==》定义一个数组,数组初始化全为1
        若i的分数比左右高,i处的孩子比i-1和i+1的糖果数要多。==》分治成左右两个规则,数组的正向反向遍历,最后取最大值进行累加即可
         */
         int len = ratings.length;
         int[] left = new int[len];
         int[] right = new int[len];
         Arrays.fill(left,1);
         Arrays.fill(right,1);
         // 正向遍历数组
         for(int i = 1; i < len; i++){
             if(ratings[i] > ratings[i - 1]){
                 left[i] = left[i - 1] + 1;
             }
         }
         int sum = 0;
         // 反向遍历数组,这里的j一定要从len-1开始,因为要开始取左右数组的最大值了
         for(int j = len - 1; j >= 0; j--){
             // 防止下标越界,所以要使用 j!= len - 1
             if(j != len -1 && ratings[j] > ratings[j+1]){
                 right[j] = right[j+1] + 1;
             }
             sum += Math.max(left[j],right[j]);
         }
         return sum;

    }
}

189. 旋转数组

时间复杂度O(N),空间复杂度O(n),题目要求空间复杂度O(1)

class Solution {
    public void rotate(int[] nums, int k) {
        /**
        分析:
        最开始的想法是保存原数组到新数组上,然后遍历新数组的倒数第k个数,输出到原数组上
         */
         int len = nums.length;
         int[] copy = new int[len];
         copy =  Arrays.copyOfRange(nums,0,len);
         // 对k进行化简
         k %= len;
         int count = 0;
         // 遍历原数组
         for(int i = len - k; i < len; i++){
             nums[count++] = copy[i];
         }
         for(int j = 0; j < len - k; j++){
             nums[count++] = copy[j];
         }
    }
}

注意:本题的特例,需要技巧,使用到了翻转数组的特性

class Solution {
    public void rotate(int[] nums, int k) {
        /**
        要求使用原地修改算法,如果是链表类型,那么很容易想到用快慢指针法
        本题是数组类型,并且这道题在考研王道中也有出现过,很明显会想到翻转数组(技巧题型)
        先整体翻转,再翻转(0,k-1),最后翻转余下的
         */
        int len = nums.length;
        k %= len;
        reverse(nums,0,len - 1);
        reverse(nums,0,k-1);
        reverse(nums,k,len - 1);

    }
    public void reverse(int[] nums,int start,int end){
        while(start < end){
            int temp = nums[start];
            nums[start] = nums[end];
            nums[end] = temp;
            start++;
            end--;
        }
    }
}

228. 汇总区间(双指针的变形)

注意:本题的核心在于使用一个变量i来联系low和high,同时判别low和high的关系,进行拼接字符串。
有点像是快慢指针,这种思想学习学习!!!
第一次没做出来就是使用slow,fast,当fast不满足条件时,无法定位到fast前一个位置。
但是本题就使用一个中间变量i,进行巧妙连接!

class Solution {
    public List<String> summaryRanges(int[] nums) {
        /**
        分析:
        若是一个区间范围表,则瞒足后一个数比前一个数大1,否则就是一个独立的数字
        基本思路是遍历数组,同时记录首尾指针,是区间范围表,那么将首尾添加到list中,否则直接添加list
        当low < high时,是一个区间
        当low = high时,是一个数
         */
         int len = nums.length;
         List<String> res = new ArrayList<>();
         int i = 0;
         while( i < len){
             // 定义low指针随i变化
             int low = i;
             // 递增i,便于使用num[i] - num[i - 1] == 1语句
             i++;
             // 找到非连续的点
             while( i < len && nums[i] - nums[i - 1] == 1){
                 i++;
             }
             // 找到非连续点的前一个
             int high = i - 1;
             // 初始化字符串为low
             StringBuilder sb = new StringBuilder(Integer.toString(nums[low]));
             // 判断low与high的关系
             if(low < high){
                 sb.append("->");
                 sb.append(Integer.toString(nums[high]));
             }
             // 记得转换为String
             res.add(sb.toString());
         }
         return res;
    }
}

605种花问题

注意:第一版是自己写的代码,主要思路是去遍历,然后扣除首尾的边界条件。在进行判断首尾的边界条件时耗费了很大的功夫(面向测试用例编程),这种做法很明显是需要优化的,能不能把首尾的边界条件做一个简单的优化?答案是可以的,给数组前加一个0.数组末加一个0,这种编程思路叫做“防御式编程”

class Solution {
    public boolean canPlaceFlowers(int[] flowerbed, int n) {
        /**
        分析:题目的意思就是在数组中寻找0,插入n个1。使得每个1之间至少间隔一个
         */
         int len = flowerbed.length;
         int count = 0;
         if(n == 0){
             return true;
         }else if(n==1 && len == 1 && flowerbed[0] == 0){
             return true;
         }
         else if(n==1 && len == 1 && flowerbed[0] == 1){
             return false;
         }
         if(len < n ){
             return false;
         }
         if(flowerbed[0] == 0 && flowerbed[1] == 0){
             flowerbed[0] = 1;
             count++;
         }
         for(int i = 1; i < len - 1; i++){
             if(flowerbed[i] == 0 && flowerbed[i - 1] == 0 && flowerbed[i + 1] == 0){
                 flowerbed[i] = 1;
                 count++;
             }
         }
         if(flowerbed[len - 2] == 0 && flowerbed[len - 1] == 0){
             flowerbed[len - 1] = 1;
             count++;
         }
         if(count >= n){
             return true;
         }
         return false;


    }
}

注意:防御式编程思想的运用!唯一的不足就是空间复杂度是O(n)

class Solution {
    public boolean canPlaceFlowers(int[] flowerbed, int n) {
        // 防御式编程,首尾两边加个0
        int len = flowerbed.length;
        int[] temp = new int[len + 2];
        // 对temp数组进行赋值操作
        for(int i = 1; i <= len; i++){
            temp[i] = flowerbed[i-1];
        } 
        // 遍历temp数组,这时候就不需要进行过多的边界判断了
        for(int i = 1; i <= len; i++){
            if(temp[i]==0&&temp[i-1]==0&&temp[i+1]==0){
                //种上花
                temp[i] = 1;
                n--;
            }
        }
        return n<=0;

    }
}

注意:若是还是想用空间复杂度是O(1)的做法,那么就要思考下之前的边界条件能不能再优化(这里的优化值得是算法思想的优化),答案肯定是可以的。对数组遍历,若当前的花坛i已经种植花了,很明显需要到i+2处进行查看是否能种植,若当前花坛是最后一个花坛或者当前花坛和下一个花坛都没有种植,那么当前位置i就可以种植,同时继续到i+2处查看是否能种植(这里解释下为甚最后一个花坛可以种植:若只有单个,最后一个花坛可以种植,若为多个,由于i+2的操作,导致倒数第二个花坛必为0,故可以种植),最后一种情况,若i没有种花,但是i+1种花了,那么肯定是要去i+3的位置去探索了。
总之,比较难想到这种边界条件的判定解法,需要一定的积累。

class Solution {
    public boolean canPlaceFlowers(int[] flowerbed, int n) {
        /**
        优化边界条件
         */
         int len = flowerbed.length;
         int i= 0;
         while( i < len){
             // 当前位置中了花
             if(flowerbed[i] == 1){
                 i += 2;
             }else if(i == len - 1 || flowerbed[i] ==0 &&flowerbed[i + 1] == 0) {
                 // 当前位置可以种,下一个位置也可以种
                 n--;
                 i += 2;
             }else{
                 // 当前位置可以种,下一个位置不可以中
                 i += 3;
             }
         }
         return n <= 0;

    }
}

665. 非递减数列

注意:本题技巧性真的强,是要理解测试案例 3 4 2 3然后根据这个测试案例做出相关的赋值操作,依次循环迭代

class Solution {
    public boolean checkPossibility(int[] nums) {
        /**
        看了题解才明白,解决本题的核心就是去理解测试案例 3 4 2 3
        以上测试案例是false,那么第一个发现nums[i] < nums[i - 1]时,应该将nums[i] = nums[i - 1],计数+1,然后继续遍历
        若计数 > 1,则说明无法改变一个元素
         */
         int count = 0;
         for(int i = 1; i < nums.length; i++){
             if(nums[i] < nums[i - 1]){
                 // 发现非递增
                 count++;
                 //判断count是否超过1
                 if(count > 1){
                     return false;
                 }
                 // 改变值
                 if(i - 2 >= 0 && nums[i] < nums[i -2] ){
                     nums[i] = nums[i - 1];
                 }
             }
         }
         return true;

    }
}

860. 柠檬水找零

class Solution {
        public boolean lemonadeChange(int[] bills) {
        //统计店员所拥有的5元和10元的数量(20元的不需要统计,
        //因为顾客只能使用5元,10元和20元,而20元是没法
        // 给顾客找零的)
        int five = 0, ten = 0;
        for (int bill : bills) {
            if (bill == 5) {
                //如果顾客使用的是5元,不用找零,5元数量加1
                five++;
            } else if (bill == 10) {
                //如果顾客使用的是10元,需要找他5元,所以
                //5元数量减1,10元数量加1
                five--;
                ten++;
            } else if (ten > 0) {
                //否则顾客使用的只能是20元,顾客使用20元的时候,
                //如果我们有10元的,要尽量先给他10元的,然后再
                //给他5元的,所以这里5元和10元数量都要减1
                ten--;
                five--;
            } else {
                //如果顾客使用的是20元,而店员没有10元的,
                //就只能给他找3个5元的,所以5元的数量要减3
                five -= 3;
            }

            //上面我们找零的时候并没有判断5元的数量,如果5元的
            //数量小于0,说明上面某一步找零的时候5元的不够了,
            //也就是说没法给顾客找零,直接返回false即可
            if (five < 0) {
                return false;
            }
        }
        return true;
    }


}

941. 有效的山脉数组

注意:以下是我的第一次解法,有很多优化的空间,比如flag重复标记最高点这个操作明显会拉低效率,完全可以在循环结束后进行判断最高点(最高点不能是第一个和最后一个元素)

class Solution {
    public boolean validMountainArray(int[] arr) {
        /**
        分析:
        在区间[1,n-2]中找到一个数,使得该数组前半部分升序,后半部分降序
         */
         int len = arr.length;
         if(len < 3){
             return false;
         }
         int i = 1;
         int flag = 0;
         while( i < len - 1){
             if( arr[i] - arr[i - 1] > 0  ){
                 // 重复标记flag,flag是最高点
                flag = i;
                 i++;
             }else if(arr[i+1] - arr[i] < 0){
                 i++;
             }else{
                 // 其余情况下,退出循环
                 break;
             }
         }
         // i到最后一个数,并且最高点符合条件(最高点要大于起点和终点)
         if( i == len - 1 && arr[flag] > arr[0] &&arr[flag] > arr[len - 1] ){
             return true;
         }
         return false;

    }
}

第二版的代码逻辑性就更好了,最高点在while循环结束后开始判断。

class Solution {
    public boolean validMountainArray(int[] arr) {
        int len = arr.length;
        int i = 0;
        while( i < len -1 && arr[i] < arr[i + 1]){
            i++;
        }
        // 判断最高点(不能是第一个元素和最后一个元素)
        if(i == 0 || i == len - 1){
            return false;
        }
        while( i < len - 1 && arr[i] > arr[i+1]){
            i++;
        }
        return i==len - 1;

    }
}

48. 旋转图像(数组转置+镜像)

注意:使用复制数组,唯一的缺点就是要去推导旋转后下标之间的关系,这种实际上比较耗费时间,从思考上是不难的,但是从推导上是难的,因此更加推荐使用第二种解法,转置+镜像解法

class Solution {
    public void rotate(int[][] matrix) {
        // 若是没有要求原地旋转,那么完全可以先复制数组,再修改
        int len = matrix.length;
        int[][] copy = new int[len][len];
        for(int i = 0; i < len; i++){
            for(int j = 0; j < len; j++){
                copy[j][len - i - 1] = matrix[i][j]; 
            }
        } 
        // 修改数组
        for(int i = 0; i < len; i++){
            for(int j = 0; j < len; j++){
                matrix[i][j] = copy[i][j]; 
            }
        } 
    }
}

升级版~!

class Solution {
    public void rotate(int[][] matrix) {
        /**
        分析:
        要求原地修改二维数组,通过观察可以发现,第一行数据变成最后一列,第二行数据变成倒数第二列,最后一行数据变成第一列。学习转置代码和镜像代码~~~
        总结规律:
        情况一:顺时针转 90 度:先转置再左右镜像
        1 2 3               7 4 1
        4 5 6               8 5 2
        7 8 9               9 6 3
        情况二:顺时针转 180 度:先上下镜像,再左右镜像(先左右再上下也可)
        1 2 3               9 8 7
        4 5 6               6 5 4
        7 8 9               3 2 1
        情况三:顺时针转 270 度:先转置再上下镜像
        1 2 3              3 6 9
        4 5 6              2 5 8
        7 8 9              1 4 7
         */
         int len  = matrix.length;
         // 先转置
         for(int i = 0; i < len; i++){
             for(int j = 0; j < i; j++){
                 int temp = matrix[i][j];
                 matrix[i][j] = matrix[j][i];
                 matrix[j][i] = temp;
             }
         }
         // 再左右镜像
         int left = 0;
         int right = len - 1;
         while( left < right){
             for(int i = 0; i < len; i++){
                 int temp = matrix[i][left];
                 matrix[i][left] = matrix[i][right];
                 matrix[i][right] = temp;
             }
             left++;
             right--;
         }
    }
}

54. 螺旋矩阵

注意:矩阵是长方形的时候还需要添加额外的判断条件,防止重复计算~

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        /**
        分析:
        这道题似曾相识,像是模拟法.分为上下左右四个区块。
        没错就是模拟法,和59题思路完全一模一样。
        class Solution {
    public int[][] generateMatrix(int n) {
        //模拟法的应用:如何解决边界条件
        //四个边界
        int l=0,r=n-1,t=0,b=n-1;
        //count存放数值
        int count = 1,val = n*n;
        //这是结果数组
        int [][] res = new int [n][n];
        while(count<=val){
            //从左往右
            for (int i = l; i <= r ; i++) {
                res[t][i] = count++;
            }
            //top边界要下移
            t++;

            //从上往下
            for (int i = t; i <= b ; i++) {
                res[i][r] = count++;
            }
            //right边界要左移
            r--;

            //从右往左
            for (int i = r; i >= l ; i--) {
                res[b][i] = count++;
            }
            //bottom边界要上移
            b--;
            //从下往上
            for (int i = b; i >= t ; i--) {
                res[i][l] = count++;
            }
            //left边界要右移
            l++;
        }
        return res;
    }
}
         */
         List<Integer> res = new ArrayList<>();
         int m = matrix.length;
         int n = matrix[0].length;
         int left = 0,right = n - 1,top = 0, bottom = m - 1;
         int total = m * n;
         while(total >= 1){
            //  total >= 1 是为了应对长方形的,比如一个长方形的长有10,宽只有3,当循环完最后一次从左到右的时候,total已经小于1了,此时的left和right由于循环得很少,向里面缩进得很少,当状态来到从右向左的时候,由于没有total >= 1,又可以执行了,但是之前这些值已经添加了。。
             // 上边界
             for(int i = left; i <= right&&total >= 1; i++){
                 res.add(matrix[top][i]);
                 total--;
             }
             // 上边界下移
             top++;
             for(int i = top; i <= bottom&&total >= 1; i++){
                 res.add(matrix[i][right]);
                 total--;
             }
             // 右边界左移
             right--;
             for(int i = right; i >= left&&total >= 1; i--){
                 res.add(matrix[bottom][i]);
                 total--;
             }
             // 下边界上移
             bottom--;
             for(int i = bottom; i >= top&&total >= 1; i--){
                 res.add(matrix[i][left]);
                 total--;
             }
             // 左边界右移
             left++;
         }
         return res;

    }
}

73. 矩阵置零(标记算法思想)

注意:使用数组,思想比较简单,空间复杂度为o(m+n)

class Solution {
    public void setZeroes(int[][] matrix) {
        /**
        分析:
        方案一:使用标记数组法。定义行列数组,若某一元素出现0.则将该行、列数组对应位置标记,然后遍历置0。时间复杂度为o(m*n)空间复杂度为O(m+n)
        方案二:使用两个临时变量,标记首行和首列是否存在0,对于非首行首列的元素置于最上方和最左方,然后遍历置0,最后根据首行首列的标记位再次置0
         */
        //  标记数组法
        int m = matrix.length;
        int n = matrix[0].length;
        boolean[] rows = new boolean[m];
        boolean[] cols = new boolean[n];
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(matrix[i][j] == 0){
                    // 标记对用的行和列
                    rows[i] = true;
                    cols[j] = true;
                }
            }
        }
        // 再次遍历
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                // 判断标记数组
                if(rows[i] || cols[j] ){
                    // 更新数组
                    matrix[i][j] = 0;
                }
            }
        }


    }
}

注意:使用标记变量,比较饶一点,空间复杂度o(1)

class Solution {
    public void setZeroes(int[][] matrix) {
        /**
        分析:
        方案一:使用标记数组法。定义行列数组,若某一元素出现0.则将该行、列数组对应位置标记,然后遍历置0。时间复杂度为o(m*n)空间复杂度为O(m+n)
        方案二:使用两个临时变量,标记首行和首列是否存在0,对于非首行首列的元素置于最上方和最左方,然后遍历置0,最后根据首行首列的标记位再次置0
         */

        //  使用两个临时变量标记首行和首列是否有0
        boolean flagRow = false;
        boolean flagCol = false;
        int m = matrix.length;
        int n = matrix[0].length;
        // 标记临时变量
        for(int i = 0; i < m; i++){
            if(matrix[i][0] == 0){
                // 标记首列
                flagCol = true;
                break;
            }
        }
        for(int i = 0; i < n; i++){
            if(matrix[0][i] == 0){
                // 标记首行
                flagRow = true;
                break;
            }
        }
        // 标记非首行非首列的元素到最左边和最上边
        for(int i = 1; i < m; i++){
            for(int j = 1; j < n; j++){
                if(matrix[i][j] == 0){
                    matrix[i][0] = 0;
                    matrix[0][j] = 0;
                }
            }
        }
        // 遍历,处理最左边和最上边的0元素
        for(int i = 1; i < m; i++){
            if(matrix[i][0] == 0){
                // 行置0
                for(int j = 1; j < n; j++){
                    matrix[i][j] = 0;
                }
            }
        }
        for(int j = 1; j < n; j++){
            if(matrix[0][j] == 0){
                // 列置0
                for(int i = 1; i < m; i++){
                    matrix[i][j] = 0;
                }
            }
        }
        // 处理首行首列的标记位
        if(flagRow){
            for(int i = 0; i < n; i++){
                matrix[0][i] = 0;
            }
        }
        if(flagCol){
            for(int i = 0; i < m; i++){
                matrix[i][0] = 0;
            }
        }




    }
}

118. 杨辉三角(抽象思维能力)

注意:本题是一个简单,但却十分的体现了抽象思维的能力。遇到一个问题,如何将文字语言转换为数学语言,如何将数学语言转换为数据结构算法。这是核心negligible!
比如杨辉三角中的首列和末列都是1,那么如何将就可以抽象成 j == 0 和 i == j,然后再去计算~
这里要注意,依旧使用下标为0,因为底层使用的是ArrayList,如果采用1,有可能会导致数组溢出问题

class Solution {
    public List<List<Integer>> generate(int numRows) {
        /**
        分析:
        初始值为1,每个数是它左上方和右上方的数的和.
        将问题抽象一下,找到规律,杨辉三角的第一列和最后一列都是1,中间的数是上一层的的j-1和j列的和。
         */
         List<List<Integer>> res = new ArrayList<>();
         for(int i = 0; i < numRows; i++){
            //  这是中间媒介
             List<Integer> temp = new ArrayList<>();
             for(int j = 0; j <= i; j++){
                 // 杨辉三角的第一列( j== 0)和最后一列(i == j)都是1
                 if(j == 0 || i == j){
                     temp.add(1);
                 }else{
                     // 否则就是去寻找上一层的j-1和j列的和
                     // 获取上一层信息
                     List<Integer> prev = res.get( i - 1);
                     // 计算和
                     temp.add(prev.get( j - 1) + prev.get(j));
                 }
             }
             // 添加到res
             res.add(temp);

         }
         return res;

    }
}

119. 杨辉三角 II

注意:使用O(rowIndex) 空间复杂度,是用到了杨辉三角的组合数公式,个人觉得没有必要掌握,所以不记录该题解。

class Solution {
    public List<Integer> getRow(int rowIndex) {
        /**
        杨辉三角的变种题,实际上还是培养抽象思维.
        如何保存上一层的信息? 这里使用了更新机制
         */
         List<Integer> res = new ArrayList<>();
         for(int i = 0; i <= rowIndex; i++){
             List<Integer> temp = new ArrayList<>();
             for(int j = 0; j <= i; j++){
                 if(j == 0 || j == i){
                     temp.add(1);
                 }else{
                     // 定位到上一层
                     temp.add(res.get(j - 1) + res.get(j));
                 }
             }
             // 更新
             res = temp;
         }
         return res;

    }
}

498. 对角线遍历(边界处理)

注意:第一次解答本题的时候,思路已经正确了,但就是边界条件一直判断不出来,包括后面的调试,也是一直出错(if判断语句应该在循环体外!)

class Solution {
    public int[] findDiagonalOrder(int[][] mat) {
        /**
        分析:
        对角线的数学特性是行下标+列下标是该层遍历的数字.
        层数遍历的数字范围为[0,m+n-2],层数下标姑且认为是row+col,若row+col是偶数,则右上遍历
        若row+col是奇数,则左下遍历。
        那么问题就换成右上遍历和左上遍历的边界角标问题了
         */
         int m = mat.length;
         int n = mat[0].length;
         int[] res = new int[m*n];
         int row = 0, col = 0;
         int index = 0;
        //  遍历m+n-1次
         for(int i = 0; i < m+n-1; i++){
             if(i % 2 == 0){
                 // 右上遍历
                 while(row >=0 && col <=  n - 1){
                     // 添加到数组
                     res[index++] = mat[row][col];
                     // 遍历在正常范围内,则row-1,col+1
                     row--;
                     col++;
                 }
                     // 发现 row越界了
                     if( col <= n-1){
                         // 修复row
                         row++;
                     }else{
                        //  发现col越界了,修复col
                        row += 2;
                        col--;
                     }
             }else{
                 // 左下遍历
                 while(row <= m - 1 && col >= 0){
                     // 添加到数组
                     res[index++] = mat[row][col];
                     // 遍历在正常范围内,则row+1,col-1
                     row++;
                     col--;
                 }
                  
                     // 发现 col越界了
                     if( row <= m - 1){
                         // 修复col
                         col++;
                     }else{
                        //  发现row越界了,修复row
                        row--;
                        col += 2;
                     }
             }
         }
         return res;

    }
}

12. 整数转罗马数字(使用数组进行枚举)

注意:第一次思路想错了,只枚举题目给的了特殊的六种情况。实际上,题目给的数字全是特殊情况,结果集就是由这些特殊情况所组合起来的,对于数字,要进行排序,然后依次判断。

class Solution {
    public String intToRoman(int num) {
        // 把阿拉伯数字与罗马数字可能出现的所有情况和对应关系,放在两个数组中
        int[] nums = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
        String[] romans = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};

        StringBuilder res = new StringBuilder();
        int index = 0;
        while (index < 13) {
            while (nums[index] <= num) {
                res.append(romans[index]);
                num -= nums[index];
            }
            index++;
        }
        return res.toString();
    }

}

13. 罗马数字转整数(哈希表+数组枚举)

注意:第一种解法使用使用了哈希表,来进行累计计算的。

class Solution {
    public int romanToInt(String s) {
        // 思路和上一题一样,用数组储存特殊情况
        // 但是这种情况下无法进行数字的累加组合,比如我扫描到了一个C,实际上有可能会是CM和CD的数字
        // 所以这种数组对应的解法在本题不适用。  真的不适用嘛???我把顺序调整为从小到大!
        // int[] nums = new int[]{1000,900,500,400,100,90,50,40,10,9,5,4,1};
        // String[] romans = new String[]{"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
        // int sum = 0;

        /**
        变换思路:
        把所有字母对应的数字(从小到大)添加到哈希表中,扫描一个就进行计算(如果前一个数比后一个数小做减法,否则做加法),这样就完美的进行了运算功能。
         */
         Map<Character,Integer> map = new HashMap<>();
        map.put('I',1);
        map.put('V',5);
        map.put('X',10);
        map.put('L',50);
        map.put('C',100);
        map.put('D',500);
        map.put('M',1000);
         int len = s.length();
         int sum = 0;
         for(int i = 0; i < len ; i++){
             // 获取前一个值
             int prev = map.get(s.charAt(i));
             // 注意边界以及判断前后数字大小关系
             if(i < len - 1 && prev < map.get(s.charAt(i+1))){
                 // 减法运算
                 sum -= prev;
             }else{
                 // 加法运算
                 sum += prev;
             }
         }
         return sum;




    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值