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;
由上可知,右值永远为正,因此最后一位必然为正。
一言蔽之,把一个小值放在大值的左边,就是做减法,否则为加法。
- 在代码实现上,可以往后看多一位,对比当前位与后一位的大小关系,从而确定当前位是加还是减法。当没有下一位时,做加法即可。
- 也可保留当前位的值,当遍历到下一位的时,对比保留值与遍历位的大小关系,再确定保留值为加还是减。最后一位做加法即可。
借鉴大佬代码如下:
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;
}
}