LeetCode编程练习

2021-01-15

在这里插入图片描述
代码如下:

class Solution {
    public boolean isPalindrome(int x) {
        int num = x;
        if (x == 0) return true;
        if (x < 0 || x % 10 == 0) return false;
        //2.颠倒数字123456
        /*
        123456 % 10 = 6 sum * 10 + 6 = 6
        12345 % 10 = 5 sum * 10 + 5 = 65
        1234 % 10 = 4 sum * 10 + 4 = 654
        */
        int sum = 0;
        while(x != 0){
            sum = sum * 10 + x % 10;
            x /= 10;
        }
        if(sum == num){
            System.out.println(" true");
        }else{
            System.out.println(" false");
        }
        return x == sum || x == sum / 10;
    }
}

===============================================================================================
在这里插入图片描述
在这里插入图片描述
思路如下:
按照题目的描述,可以总结如下规则:

		罗马数字由 I,V,X,L,C,D,M 构成;
		当小值在大值的左边,则减小值,如 IV=5-1=4;
		当小值在大值的右边,则加小值,如 VI=5+1=6;
		由上可知,右值永远为正,因此最后一位必然为正。
		一言蔽之,把一个小值放在大值的左边,就是做减法,否则为加法。
  1. 在代码实现上,可以往后看多一位,对比当前位与后一位的大小关系,从而确定当前位是加还是减法。当没有下一位时,做加法即可。
  2. 也可保留当前位的值,当遍历到下一位的时,对比保留值与遍历位的大小关系,再确定保留值为加还是减。最后一位做加法即可。
    在这里插入图片描述
    借鉴大佬代码如下:
class Solution {
    public int romanToInt(String s) {
        s = s.replace("IV","a");
        s = s.replace("IX","b");
        s = s.replace("XL","c");
        s = s.replace("XC","d");
        s = s.replace("CD","e");
        s = s.replace("CM","f");
        
        int result = 0;
        for (int i=0; i<s.length(); i++) {
            result += which(s.charAt(i));
        }
        return result;
    }

    public int which(char ch) {
        switch(ch) {
            case 'I': return 1;
            case 'V': return 5;
            case 'X': return 10;
            case 'L': return 50;
            case 'C': return 100;
            case 'D': return 500;
            case 'M': return 1000;
            case 'a': return 4;
            case 'b': return 9;
            case 'c': return 40;
            case 'd': return 90;
            case 'e': return 400;
            case 'f': return 900;
        }
        return 0;
    }
}

===============================================================================================

在这里插入图片描述
思路如下:

很明显每个柱子顶部可以储水的高度为:该柱子的左右两侧最大高度的较小者减去此柱子的高度。
因此我们只需要遍历每个柱子,累加每个柱子可以储水的高度即可。

代码如下:

class Solution {
    public int trap(int[] height) {
        int res = 0;
        // 遍历每个柱子
        for (int i = 1; i < height.length - 1; i++) {
            int leftMax = 0, rightMax = 0;
            // 计算当前柱子左侧的柱子中的最大高度
            for (int j = 0; j <= i; j++) {
                leftMax = Math.max(leftMax, height[j]);
            }
            // 计算当前柱子右侧的柱子中的最大高度
            for (int j = i; j < height.length; j++) {
                rightMax = Math.max(rightMax, height[j]);
            }
            // 结果中累加当前柱子顶部可以储水的高度,
            // 即 当前柱子左右两边最大高度的较小者 - 当前柱子的高度。
            res += Math.min(leftMax, rightMax) - height[i];
        }
        return res;
    }
}

2021-01-19

在这里插入图片描述
思路:

输入: “Hello World”,从右到左进行检索
如果没有字符等于" "(空格),就记1
如果遇到空格就return退出程序

class Solution {
    public int lengthOfLastWord(String s) {
        int count = 0;
        for(int i = s.length() - 1;i >= 0;i--){
        
            if(s.charAt(i) !=' '){
                count++;
            }else if(count != 0){
                return count;
            }
        }
        return count;
    }
}

在这里插入图片描述
思路:

num1的第i位(高位从0开始)和num2的第j位相乘的结果在乘积中的位置是[i+j, i+j+1]
例: 123 * 45, 123的第1位 2 和45的第0位 4 乘积 08 存放在结果的第[1, 2]位中

      index:    0 1 2 3 4                          
                    1 2 3
                *     4 5
                ---------
                      1 5
                    1 0
                  0 5
                ---------
                  0 6 1 5
                    1 2
                  0 8
                0 4
                ---------
                0 5 5 3 5
    这样我们就可以单独都对每一位进行相乘计算把结果存入相应的index中

大佬代码

class Solution {
    public String multiply(String num1, String num2) {
        
        int n1 = num1.length()-1;
        int n2 = num2.length()-1;
        if(n1 < 0 || n2 < 0) return "";
        int[] mul = new int[n1+n2+2];
        
        for(int i = n1; i >= 0; --i) {
            for(int j = n2; j >= 0; --j) {
                int bitmul = (num1.charAt(i)-'0') * (num2.charAt(j)-'0');      
                bitmul += mul[i+j+1]; 
                // 先加低位判断是否有新的进位
                
                mul[i+j] += bitmul / 10;
                mul[i+j+1] = bitmul % 10;
            }
        }
        
        StringBuilder sb = new StringBuilder();
        int i = 0;
        // 去掉前导0
        while(i < mul.length-1 && mul[i] == 0) 
            i++;
        for(; i < mul.length; ++i)
            sb.append(mul[i]);
        return sb.toString();
    }
}

在这里插入图片描述
思路

如果您的字符串 S 包含一个重复的子字符串,那么这意味着您可以多次 “移位和换行”`您的字符串,并使其与原始字符串匹配。
例如:abcabc
移位一次:cabcab
移位两次:bcabca
移位三次:abcabc
现在字符串和原字符串匹配了,所以可以得出结论存在重复的子串。
基于这个思想,可以每次移动k个字符,直到匹配移动 length - 1 次。但是这样对于重复字符串很长的字符串,效率会非常低。在 LeetCode 中执行时间超时了。
为了避免这种无用的环绕,可以创建一个新的字符串 str,它等于原来的字符串 S 再加上 S 自身,这样其实就包含了所有移动的字符串。
比如字符串:S = acd,那么 str = S + S = acdacd
acd 移动的可能:dac、cda。其实都包含在了 str 中了。就像一个滑动窗口
一开始 acd (acd) ,移动一次 ac(dac)d,移动两次 a(cda)cd。循环结束
所以可以直接判断 str 中去除首尾元素之后,是否包含自身元素。如果包含。则表明存在重复子串。
秀的头皮发麻!!!!!!!

膜拜大佬的代码:

  • 精髓版
class Solution {
   public boolean repeatedSubstringPattern(String s) {
        String str = s + s;
        return str.substring(1, str.length() - 1).contains(s);
}
}
  • 暴力解法
public  boolean repeatedSubstringPattern(String s) {
        for(int i = 1; i < s.length(); i++) {
            String str = rotate(s.toCharArray(),i);
            if(s.equals(str)) return true;
        }
        return false;
    }


    public  String rotate(char[] nums, int k) {
        k = k % nums.length;
        reverse(nums, 0, nums.length - 1);
        reverse(nums, 0, k - 1);
        reverse(nums, k, nums.length - 1);
        return String.valueOf(nums);
    }

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

2021-01-22

在这里插入图片描述
思路:

我们可以直接创建一个大小为 26 的桶,记录每种字符的数量。每次提取最长的上升或下降字符串时,我们直接顺序或逆序遍历这个桶。
具体地,在遍历桶的过程中,如果当前桶的计数值不为零,那么将当前桶对应的字符加入到答案中,并将当前桶的计数值减一即可。我们重复这一过程,直到答案字符串的长度与传入的字符串的长度相等。

class Solution {
    public String sortString(String s) {
        int[] num = new int[26];
        for (int i = 0; i < s.length(); i++) {
            num[s.charAt(i) - 'a']++;
        }

        StringBuffer ret = new StringBuffer();
        while (ret.length() < s.length()) {
            for (int i = 0; i < 26; i++) {
                if (num[i] > 0) {
                    ret.append((char) (i + 'a'));
                    num[i]--;
                }
            }
            for (int i = 25; i >= 0; i--) {
                if (num[i] > 0) {
                    ret.append((char) (i + 'a'));
                    num[i]--;
                }
            }
        }
        return ret.toString();
    }
}

在这里插入图片描述
思路:

从前面开始遍历,遇到问号就对比前面和后面的 用一个不与前面和后面一致的字符代替就好了

class Solution {
    public String modifyString(String s) {
        char[] chars = s.toCharArray();

        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == '?') {
                //前面一个字符  如果当前是第0个的话 字符就为‘ ’
                char ahead = i == 0 ? ' ' : chars[i - 1];
                //后面一个字符  如果当前是最后一个的话 字符就为‘ ’
                char behind  = i == chars.length - 1 ? ' ' : chars[i + 1];
                //从a开始比较  如果等于前面或者后面的话 就+1
                char temp = 'a';
                while (temp == ahead || temp == behind ) {
                    temp++;
                }
                //找到目标字符后 做替换
                chars[i] = temp;
            }
        }
        return new String(chars);
    }
}

在这里插入图片描述

思路:

例如:abcabc
移位一次:cabcab
移位两次:bcabca
移位三次:abcabc
现在字符串和原字符串匹配了,所以可以得出结论存在重复的子串。
基于这个思想,可以每次移动k个字符,直到匹配移动 length - 1 次。但是这样对于重复字符串很长的字符串,效率会非常低。在 LeetCode 中执行时间超时了。
为了避免这种无用的环绕,可以创建一个新的字符串 str,它等于原来的字符串 S 再加上 S 自身,这样其实就包含了所有移动的字符串。
比如字符串:S = acd,那么 str = S + S = acdacd
acd 移动的可能:dac、cda。其实都包含在了 str 中了。就像一个滑动窗口
一开始 acd (acd) ,移动一次 ac(dac)d,移动两次 a(cda)cd。循环结束
所以可以直接判断 str 中去除首尾元素之后,是否包含自身元素。如果包含。则表明存在重复子串。

大佬代码:

class Solution {
   public boolean repeatedSubstringPattern(String s) {
        String str = s + s;
        return str.substring(1, str.length() - 1).contains(s);
	}
}

暴力解法:

//暴力代码
public  boolean repeatedSubstringPattern(String s) {
        for(int i = 1; i < s.length(); i++) {
            String str = rotate(s.toCharArray(),i);
            if(s.equals(str)) return true;
        }
        return false;
    }


    public  String rotate(char[] nums, int k) {
        k = k % nums.length;
        reverse(nums, 0, nums.length - 1);
        reverse(nums, 0, k - 1);
        reverse(nums, k, nums.length - 1);
        return String.valueOf(nums);
    }

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


2021-01-27

在这里插入图片描述

class Solution {
    public int[] sortedSquares(int[] nums) {
        int len = nums.length;
        int [] arr = new int[len];
        for(int i =0 ; i<len; i++){
            arr[i] = nums[i]*nums[i];
        }
        Arrays.sort(arr);
        return arr;
    }
}

在这里插入图片描述

没有必要求出每种奇数长度数组的情况,只需判断每个元素在奇数长度数组中出现的次数即可
left求法:对当前元素arr[i]来说,前面有i个元素,想要构成连续数组,可在arr[i]左面连续取0,1,2,…,i个元素,所以共有left=i+1种选择方法
right求法:arr[i]后有n-i-1个元素,想要构成连续数组,可在arr[i]右面连续取元素,共有right=n-i种选择方法(算上取0个元素)
left_odd, right_odd:为可选择数/2 (左面选奇数个元素右面选奇数个元素加上本身为奇数长度数组)
left_even, right_even:为(可选择数+1)/2 (左面选偶数个元素右面选偶数个元素加上本身为奇数长度数组)
sum:对每个arr[i]求它出现在奇数长度子数组中的次数,乘本身的值,最后求和

class Solution {
    public int sumOddLengthSubarrays(int[] arr) {
        int length = arr.length, sum = 0;
        for(int i=0;i<length;i++){  //遍历数组
            int left = i+1, right = length-i;
            int left_odd = left/2, right_odd = right/2;
            int left_even = (left + 1)/2, right_even = (right + 1)/2;
            sum += arr[i]*(left_odd*right_odd + left_even*right_even);
        }
        return sum;
    }
}

在这里插入图片描述

class Solution {
    public int majorityElement(int[] nums) {
int count=1;
        if(nums.length==1){
            return nums[0];
        }
        Arrays.sort(nums);
        for(int i=1;i<nums.length;i++){
            if(nums[i]==nums[i-1]){
                count++;
            }else{
                count=1;
            }
            if(count>(nums.length/2)){
                return nums[i];
            }
        }
        return -1;
    }
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值