目录
1.交替合并字符串
题目描述:给你两个字符串word1和word。请你从word1开始,通过交替添加字母来合并字符串。如果一个字符串比另一个字符串长,就将多出来的字母追加到合并后字符串的末尾。
1.1 解法一:
class Solution { // 定义一个名为Solution的类
public String mergeAlternately(String word1, String word2) { // 定义一个公共方法mergeAlternately,接受两个字符串参数word1和word2
// 如果word1的长度为0,说明word1为空字符串,直接返回word2
if(word1.length()==0){
return word2;
}
// 如果word2的长度为0,说明word2为空字符串,直接返回word1
else if(word2.length()==0){
return word1;
}
else{
int i = 0; // 初始化一个索引变量i,用于遍历word1和word2
StringBuilder word3 = new StringBuilder(); // 创建一个StringBuilder对象word3,用于构建最终的结果字符串
// 当word1或word2中至少有一个还有剩余字符时,执行循环
while(word1.length() > i || word2.length() > i){
// 如果word1还有剩余字符,将当前索引i对应的字符添加到word3中
if(word1.length() > i ){
word3.append(word1.charAt(i));
}
// 如果word2还有剩余字符,将当前索引i对应的字符添加到word3中
if(word2.length() > i ){
word3.append(word2.charAt(i));
}
i++; // 索引i自增,准备处理下一个字符
}
return word3.toString(); // 将StringBuilder对象word3转换为普通字符串并返回
}
}
}
1.2 解法二:
class Solution {
public String mergeAlternately(String word1, String word2) {
if(word1.length()==0){
return word2;
}else if(word2.length()==0){
return word1;
}else{
int i = 0;
StringBuilder word3 = new StringBuilder();
while(word1.length() > i || word2.length() > i){
if(word1.length() > i ){
word3.append(word1.charAt(i));
}
if(word2.length() > i ){
word3.append(word2.charAt(i));
}
i++;
}
return word3.toString();
}
}
}
2.找不同
题目描述:给定两个字符串s和t,它们只包含小写字母,字符串t由字符串s随机重排,然后在随机位置添加一个字母。
请找出在t中被添加的字母。
2.1解法一:
class Solution {
public char findTheDifference(String s, String t) {
// 创建一个长度为26的数组来计数每个字母出现的次数
int[] cnt = new int[26];
// 遍历字符串s,增加对应字母的计数
for (char c : s.toCharArray()) {
cnt[c - 'a']++;
}
// 遍历字符串t,减少对应字母的计数
// 如果计数小于0,说明这个字母在t中存在但在s中不存在
for (char c : t.toCharArray()) {
cnt[c - 'a']--;
if (cnt[c - 'a'] < 0) {
return c; // 返回找到的字符
}
}
// 如果代码执行到这里,说明s和t是相同的,返回一个特殊字符或抛出异常
throw new IllegalArgumentException("The strings s and t are the same.");
}
}
3.找出字符串中第一个匹配项的下标
题目描述:给你两个字符串haystack和needle,请你在haystack字符串中找出needle字符串的第一个匹配项的下标(下标从0开始)。如果needle不是haystack的一部分,则返回-1。
3.1解法一:
class Solution {
public int strStr(String haystack, String needle) {
// 将主串和子串分别转换为字符数组,这样可以避免在后续比较中重复调用charAt()方法
char[] h = haystack.toCharArray();
char[] n = needle.toCharArray();
// 主循环:遍历主串,注意终止条件是主串长度减去子串长度,因为子串长度大于剩余的主串长度时,不可能再找到匹配
for(int i=0; i <= haystack.length() - needle.length(); i++){
// k 指向主串的当前字符,j 指向子串的起始字符
int k = i;
int j = 0;
// 内循环:比较主串和子串的字符
while(j < needle.length() && h[k] == n[j]){
k++; // 主串指针后移
j++; // 子串指针后移
}
// 如果子串的所有字符都已经比较完(即j已经等于needle.length()),则说明找到了匹配的子串
if(j == needle.length())
return i; // 返回子串在主串中的起始位置
}
// 如果遍历完主串都没有找到匹配的子串,则返回-1
return -1;
}
}
4. 有效的字母异位词
题目描述:给定两个字符串s和t,编写一个函数来判断t是否是s的字母异位词。
注意:若s和t中每个字符出现的次数都相同,则称s和t互为字母异位词。
4.1解法一:(这题跟第2题的解法有些相似)
class Solution {
public boolean isAnagram(String s, String t) {
// 如果两个字符串的长度不同,它们不可能是字母异位词
if (s.length() != t.length()) {
return false;
}
// 创建一个长度为 26 的数组来记录每个小写字母出现的次数
int[] counts = new int[26];
// 遍历字符串 s,增加每个字母的计数
for (char ch : s.toCharArray()) {
// 将字符转换为小写,并增加对应字母的计数
counts[ch - 'a']++;
}
// 遍历字符串 t,减少每个字母的计数
for (char ch : t.toCharArray()) {
// 将字符转换为小写,并减少对应字母的计数
counts[ch - 'a']--;
// 如果计数小于 0,说明 t 中包含的某个字母比 s 中多,不是字母异位词
if (counts[ch - 'a'] < 0) {
return false;
}
}
// 如果以上两个循环都没有返回 false,说明 t 是 s 的字母异位词
return true;
}
}
5.重复的子字符串
题目描述:给定一个非空的字符串s,检查是否可以通过由它的一个子串重复多次构成。
5.1.解法一:
// 定义一个名为Solution的类
class Solution {
// 定义一个公共方法repeatedSubstringPattern,接收一个字符串s作为参数
// 返回值为boolean类型,表示字符串s是否可以通过重复其子字符串来形成
public boolean repeatedSubstringPattern(String s) {
// 将字符串s拼接成两倍长度的字符串str
String str = s + s;
// 检查拼接后的字符串(除了首尾字符)是否包含原字符串s
// 如果包含,说明原字符串s可以通过重复某个子串来形成
// 注意:substring(1, str.length() - 1)排除了首尾字符,是为了避免匹配到完整的s+s
return str.substring(1, str.length() - 1).contains(s);
}
}
6.移动零
给定一个数组nums,编写一个函数将所有0移动到数组的末尾,同时保持非零元素的相对顺序。
请注意,必须在不复制数组的情况下原地对数组进行操作。
6.1解法一:
class Solution {
public void moveZeroes(int[] nums) {
// 外层循环遍历数组
for(int j=0; j<nums.length; j++){
// 内层循环从数组开头开始,检查每个元素是否为0
for(int i=0; i<nums.length-1; i++){
// 如果当前元素为0
if(nums[i]==0){
// 交换当前元素和下一个元素
int tmp = nums[i+1];
nums[i+1] = nums[i];
nums[i] = tmp;
}
}
}
// 这里存在一个问题:方法的时间复杂度为O(n^2),并且只能处理相邻的0和非0元素。
// 更好的方法是一次遍历数组,将所有非零元素移到前面,同时记录0的个数,
// 然后将剩余的位置用0填充。这样可以将时间复杂度降低到O(n)。
}
}
6.2解法二:
class Solution {
public void moveZeroes(int[] nums) {
int count = 0; // 记录0的个数
// 遍历数组,将所有非零元素移到前面
for (int i = 0; i < nums.length; i++) {
if (nums[i] != 0) {
nums[count] = nums[i]; // 将非零元素放到正确的位置
count++; // 增加非零元素的计数
}
}
// 将剩余的位置用0填充
while (count < nums.length) {
nums[count] = 0;
count++;
}
}
}
7.加一
给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位,数组中每个元素只存储单个数字。
你可以假设除了整数0以外,这个整数不会以零开头。
7.1解法一:
// 定义一个Solution类
class Solution {
// 定义plusOne方法,输入一个整数数组digits,输出加1后的整数数组
public int[] plusOne(int[] digits) {
// 从数组的最后一位开始遍历,因为加1操作是从最低位开始的
for(int i = digits.length-1; i >= 0; i--){
// 将当前位加1
digits[i]++;
// 对当前位取模10,确保每位的值在0-9之间
digits[i] = digits[i] % 10;
// 如果当前位不为0,说明没有发生进位,直接返回加1后的数组
if(digits[i] != 0) return digits;
}
// 如果循环结束还没有返回,说明原数组的所有位都是9,发生了进位
// 创建一个比原数组长度多1的新数组,用于存放进位
digits = new int[digits.length + 1];
// 将新数组的最高位(索引为0的位置)设为1,表示进位
digits[0] = 1;
// 返回新数组
return digits;
}
}
作者:YHHZW
链接:https://leetcode.cn/problems/plus-one/solutions/4481/java-shu-xue-jie-ti-by-yhhzw/
来源:力扣(LeetCode)
7.2解法二:
class Solution {
public int[] plusOne(int[] digits) {
int n = digits.length;
for (int i = n - 1; i >= 0; --i) {
if (digits[i] != 9) {
++digits[i];
for (int j = i + 1; j < n; ++j) {
digits[j] = 0;
}
return digits;
}
}
// digits 中所有的元素均为 9
int[] ans = new int[n + 1];
ans[0] = 1;
return ans;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/plus-one/solutions/1057162/jia-yi-by-leetcode-solution-2hor/
来源:力扣(LeetCode)
73解法三:(根据解法二改编)
class Solution {
public int[] plusOne(int[] digits) {
for(int i = digits.length-1;i>=0;i--){
if(digits[i] != 9){
digits[i]++;
return digits;
}else {
digits[i] = 0;
}
}
int[] ans = new int[digits.length+1];
ans[0] = 1;
return ans;
}
}
8.数组元素积的符号
题目描述:已知函数signFunc(x)将根据x的正负返回特定值:
如果x是正数,返回1
如果x是负数,返回-1
如果x等于0,返回0
给你一个整数数组nums。令product为数组nums中所有元素值的乘积
返回signFunc(product)
8.1解法一:
class Solution {
public int arraySign(int[] nums) {
int negativesCount = 0;
for (int num : nums) {
if (num < 0) {
negativesCount++;
} else ifa (num == 0) {
return 0; // 如果数组中有零,则直接返回零
}
}
// 如果负数的数量是偶数,则返回1;如果是奇数,则返回-1
return negativesCount % 2 == 0 ? 1 : -1;
}
}
8.2解法二:
// Solution类包含了arraySign方法
class Solution {
// arraySign方法接受一个整数数组nums作为参数
public int arraySign(int[] nums) {
// 初始化一个变量sign,用于记录乘积的符号,初始值为1(表示正数)
int sign = 1;
// 遍历数组nums
for(int i = 0; i <= nums.length - 1; i++){
// 如果当前元素是0,则直接返回0,因为任何数与0相乘都是0
if(nums[i] == 0)
return 0;
// 如果当前元素是负数,则改变乘积的符号(由正变负或由负变正)
if(nums[i] < 0)
sign = -sign;
// 循环结束后,返回最终的符号值
}
return sign;
}
}
9. 判断能否形成等差数列
给你一个数字数组arr
如果一个数列中,任意相邻两项的差总等于同一个常数,那么这个数列就称为等差数列
如果可以重新排列数组形成等差数列,请返回true;否则,返回false
9.1解法一:
import java.util.Arrays;
class Solution {
public boolean canMakeArithmeticProgression(int[] arr) {
// 对数组进行排序
Arrays.sort(arr);
// 检查排序后的数组是否形成等差数列
int d = arr[1] - arr[0]; // 计算第一个公差
for (int i = 2; i < arr.length; i++) {
if (arr[i] - arr[i - 1] != d) {
// 如果发现公差不一致,尝试使用负公差重新检查
d = -(arr[i] - arr[i - 1]);
for (int j = 1; j < i; j++) {
if (arr[j] - arr[j - 1] != d) {
// 如果不是所有相邻元素的差都等于新的公差,则不是等差数列
return false;
}
}
// 如果所有相邻元素的差都等于新的公差,则是等差数列
return true;
}
}
// 所有相邻元素的差都等于第一个公差,是等差数列
return true;
}
}
10.单调数列
如果数组是单调递增或单调递减的,那么它是单调的
如果对于所有i<=j,nums[i]<=nums[j],那么数组nums是单调递增的
如果对于所有i<=j,nums[i]>=nums[j],那么数组nums是单调递减的
当给定的数组nums是单调数组时返回true,否则返回false
10.1解法一:
class Solution {
public boolean isMonotonic(int[] nums) {
boolean increasing = true;
boolean decreasing = true;
for (int i = 1; i < nums.length; i++) {
if (nums[i] < nums[i - 1]) {
increasing = false;
}
if (nums[i] > nums[i - 1]) {
decreasing = false;
}
}
// 数组要么是递增的,要么是递减的
return increasing || decreasing;
}
}
11.罗马数字转整数
罗马数字包含以下七种字符: I
, V
, X
, L
,C
,D
和 M
。
字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000
例如, 罗马数字 2
写做 II
,即为两个并列的 1 。12
写做 XII
,即为 X
+ II
。 27
写做 XXVII
, 即为 XX
+ V
+ II
。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII
,而是 IV
。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX
。这个特殊的规则只适用于以下六种情况:
I
可以放在V
(5) 和X
(10) 的左边,来表示 4 和 9。X
可以放在L
(50) 和C
(100) 的左边,来表示 40 和 90。C
可以放在D
(500) 和M
(1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。
11.1解法一:
class Solution {
// 罗马数字到整数的转换方法
public int romanToInt(String s) {
// 初始化罗马数字对应的整数值的计数器
int Icount=0; // 'I' 的计数器
int Vcount=0; // 'V' 的计数器
int Xcount=0; // 'X' 的计数器
int Lcount=0; // 'L' 的计数器
int Ccount=0; // 'C' 的计数器
int Dcount=0; // 'D' 的计数器
int Mcount=0; // 'M' 的计数器
// 用于暂存某些特殊组合(如 IV, IX 等)转换成的整数值
int number = 0;
// 遍历罗马数字字符串
for(int i=0; i<s.length(); i++){
// 根据当前字符进行不同的处理
switch (s.charAt(i)){
case 'I':
// 如果下一个字符是 'V',则当前 'I' 表示 4,并将索引前进一位
if(i+1<= s.length()-1 && 'V'==s.charAt(i+1) ){
number += 4;
i++; // 注意:这里手动增加了索引,意味着下一次循环会跳过下一个字符
}
// 如果下一个字符是 'X',则当前 'I' 表示 9,并将索引前进一位
else if(i+1<= s.length()-1 && 'X'==s.charAt(i+1) )
{
number += 9;
i++; // 同样手动增加索引
}
// 否则,'I' 表示 1
else
Icount++;
break;
// 其他罗马数字字符的处理类似...
case 'V': Vcount++; break; // 'V' 表示 5
case 'X':
if(i+1<= s.length()-1 && 'L'==s.charAt(i+1) ){
number += 40;
i++;
}
else if(i+1<= s.length()-1 && 'C'==s.charAt(i+1) ) {
number += 90;
i++;
}
else
Xcount++; // 'X' 表示 10
break;
case 'L': Lcount++; break; // 'L' 表示 50
case 'C':
if(i+1<= s.length()-1 && 'D'==s.charAt(i+1)) {
number += 400;
i++;
}
else if(i+1<= s.length()-1 && 'M'==s.charAt(i+1) ) {
number += 900;
i++;
}
else
Ccount++; // 'C' 表示 100
break;
case 'D': Dcount++; break; // 'D' 表示 500
case 'M': Mcount++; break; // 'M' 表示 1000
}
}
// 将所有罗马数字字符的计数转换成整数,并加上特殊组合转换的整数值
return Icount*1 + Vcount*5 + Xcount*10 + Lcount*50 + Ccount*100 + Dcount*500 + Mcount*1000 + number;
}
}
12.最后一个单词的长度
题目描述:给你一个字符串s,由若干单词组成,单词前后用一些空格字符隔开,返回字符串中最后一个单词的长度。
单词是指仅由字母组成,不包含任何空格字符的最大子字符串。
12.1解法一:
class Solution {
// 计算给定字符串s中最后一个单词的长度
public int lengthOfLastWord(String s) {
// 去除字符串s两端的空格,并找到去除空格后字符串中最后一个空格的位置
int last = s.trim().lastIndexOf(' ');
// 返回最后一个单词的长度
// 这是通过计算去除空格后字符串的总长度减去最后一个空格的位置再减1得到的
// 如果字符串s为空或者只包含空格,则lastIndexOf会返回-1,此时计算得到的长度将是0
return s.trim().length() - 1 - last;
}
}
12.2解法二:
class Solution {
public int lengthOfLastWord(String s) {
// 使用空格分割字符串s,得到一个包含所有单词的数组
String[] words = s.split(" ");
// 如果数组为空(即字符串s为空或只包含空格),则最后一个单词的长度为0
if (words.length == 0) {
return 0;
}
// 返回最后一个单词的长度
return words[words.length - 1].length();
}
}
13. 转换成小写字母
题目描述:给你一个字符串s,将该字符串中的大写字母转换成相同的小写字母,返回新的字符串
13.1解法一:
class Solution {
public String toLowerCase(String s) {
return s.toLowerCase();
}
}
13.2解法二:
// 定义一个名为Solution的类
class Solution {
// 定义一个公开的方法toLowerCase,它接受一个字符串s作为参数,并返回转换后的字符串
public String toLowerCase(String s) {
// 创建一个字符数组s1,其长度与输入字符串s相同,用于存储转换后的小写字符
char[] s1 = new char[s.length()];
// 初始化一个整数i,用于遍历字符数组s1
int i = 0;
// 使用增强型for循环遍历输入字符串s中的每个字符
for (char ch : s.toCharArray()) {
// 检查当前字符ch是否是大写字母(ASCII码值在'A'和'Z'之间)
if (ch >= 'A' && ch <= 'Z') {
// 如果是大写字母,则将其转换为小写字母(ASCII码值加32)并存储在s1数组的当前位置
s1[i] = (char)(ch + 32);
} else {
// 如果不是大写字母(可能是小写字母或非字母字符),则直接将其存储在s1数组的当前位置
s1[i] = ch;
}
// 递增索引i,以便在下一次循环迭代中将下一个字符存储在s1数组的下一个位置
i++;
}
// 使用字符数组s1创建一个新的字符串,并返回它
// 这个新字符串包含了原始字符串s中所有大写字母的小写形式
return new String(s1);
}
}
14.棒球比赛
你现在是一场采用特殊赛制棒球比赛的记录员。这场比赛由若干回合组成,过去几回合的得分可能会影响以后几回合的得分。
比赛开始时,记录是空白的。你会得到一个记录操作的字符串列表ops,其中 ops[i] 是你需要记录的第 i 项操作,ops遵循下述规则:
- 整数
x
- 表示本回合新获得分数x
"+"
- 表示本回合新获得的得分是前两次得分的总和。题目数据保证记录此操作时前面总是存在两个有效的分数。"D"
- 表示本回合新获得的得分是前一次得分的两倍。题目数据保证记录此操作时前面总是存在一个有效的分数。"C"
- 表示前一次得分无效,将其从记录中移除。题目数据保证记录此操作时前面总是存在一个有效的分数。
请你返回记录中所有得分的总和。
14.1解法一:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
class Solution {
// 计算得分的方法
public int calPoints(String[] operations) {
// 创建一个ArrayList来存储得分
List<Integer> list = new ArrayList<>();
// 索引i用来追踪list中当前要操作的位置
int i = 0;
// 遍历operations数组中的每个操作
for(int j=0; j<operations.length; j++){
// 根据操作类型执行相应的动作
switch (operations[j]){
// "+"操作:将当前元素和前一个元素的和添加到list的当前位置
case "+":
// 如果list中至少有两个元素,则进行加法操作
if (i >= 2) {
list.add(i, list.get(i-1) + list.get(i-2));
} else {
// 否则,直接添加当前元素(应该是一个数字)
list.add(i, Integer.valueOf(operations[j]));
}
// 更新索引i
i++;
break;
// "C"操作:撤销上一步的操作,即删除list中的最后一个元素
case "C":
// 如果list不为空,则删除最后一个元素
if (!list.isEmpty()) {
list.remove(--i); // 先减少i的值,再删除元素
}
break;
// "D"操作:将当前元素翻倍后添加到list的当前位置
case "D":
// 如果list至少有一个元素,则进行翻倍操作
if (!list.isEmpty()) {
list.add(i, list.get(i-1) * 2);
} else {
// 否则,直接添加当前元素(应该是一个数字)
list.add(i, Integer.valueOf(operations[j]));
}
// 更新索引i
i++;
break;
// 默认操作:将当前元素(应该是一个数字)添加到list的当前位置
default:
list.add(i, Integer.valueOf(operations[j]));
// 更新索引i
i++;
break;
}
}
// 使用Iterator遍历list并计算所有元素的和
Iterator<Integer> it = list.iterator();
Integer score = 0;
while(it.hasNext()){
score += (Integer)it.next();
}
// 返回得分
return score;
}
}
15.机器人能否返回原点
在二维平面上,有一个机器人从原点 (0, 0)
开始。给出它的移动顺序,判断这个机器人在完成移动后是否在 (0, 0)
处结束。
移动顺序由字符串 moves
表示。字符 move[i]
表示其第 i
次移动。机器人的有效动作有 R
(右),L
(左),U
(上)和 D
(下)。
如果机器人在完成所有动作后返回原点,则返回 true
。否则,返回 false
。
注意:机器人“面朝”的方向无关紧要。 “R”
将始终使机器人向右移动一次,“L”
将始终向左移动等。此外,假设每次移动机器人的移动幅度相同。
15.1解法一:
class Solution {
// 方法:判断移动是否回到原点
public boolean judgeCircle(String moves) {
// 初始化X轴和Y轴的坐标为(0,0),即起点
int axisX = 0; // X轴坐标
int axisY = 0; // Y轴坐标
// 遍历moves字符串中的每个字符
for (char ch : moves.toCharArray()) {
// 根据字符判断移动方向,并更新坐标
switch (ch) {
case 'U': // 向上移动,Y轴坐标增加
axisY++;
break;
case 'D': // 向下移动,Y轴坐标减少
axisY--;
break;
case 'L': // 向左移动,X轴坐标减少
axisX--;
break;
case 'R': // 向右移动,X轴坐标增加
axisX++;
break;
}
}
// 如果最终X轴和Y轴的坐标都是0,则返回true,表示回到了起点
// 否则返回false,表示没有回到起点
if (axisX == 0 && axisY == 0)
return true;
else
return false;
}
}
16.找出井字棋的获胜者
题目描述:
A 和 B 在一个 3 x 3 的网格上玩井字棋。
井字棋游戏的规则如下:
- 玩家轮流将棋子放在空方格 (" ") 上。
- 第一个玩家 A 总是用 "X" 作为棋子,而第二个玩家 B 总是用 "O" 作为棋子。
- "X" 和 "O" 只能放在空方格中,而不能放在已经被占用的方格上。
- 只要有 3 个相同的(非空)棋子排成一条直线(行、列、对角线)时,游戏结束。
- 如果所有方块都放满棋子(不为空),游戏也会结束。
- 游戏结束后,棋子无法再进行任何移动。
给你一个数组 moves
,其中每个元素是大小为 2
的另一个数组(元素分别对应网格的行和列),它按照 A 和 B 的行动顺序(先 A 后 B)记录了两人各自的棋子位置。
如果游戏存在获胜者(A 或 B),就返回该游戏的获胜者;如果游戏以平局结束,则返回 "Draw";如果仍会有行动(游戏未结束),则返回 "Pending"。
你可以假设 moves
都 有效(遵循井字棋规则),网格最初是空的,A 将先行动。
16.1解法一:
// 类名:Solution
class Solution {
// 方法名:tictactoe
// 参数:moves,一个二维数组,表示每一步棋的位置,其中moves[i][0]和moves[i][1]分别表示第i步棋的行和列。
// 返回值:一个字符串,表示游戏的胜负情况或状态。
public String tictactoe(int[][] moves) {
// 初始化一个3x3的二维字符数组,表示井字棋的棋盘。
char[][] game = new char[3][3];
// 初始化一个字符变量,表示当前下棋的玩家,初始为'A'。
char step = 'A';
// 遍历moves数组,根据每一步的位置在棋盘上放置棋子。
for(int i=0;i<moves.length;i++){
// 如果当前位置没有被玩家'B'(即'O')占据,并且当前玩家是'A',则在该位置放置'X'。
if( game[moves[i][0]][moves[i][1]] != 'O' && step=='A' )
{
game[moves[i][0]][moves[i][1]] = 'X';
step='B'; // 切换到下一个玩家'B'。
}
// 如果当前位置没有被玩家'A'(即'X')占据,并且当前玩家是'B',则在该位置放置'O'。
else if(game[moves[i][0]][moves[i][1]] != 'X' && step=='B')
{
game[moves[i][0]][moves[i][1]] = 'O';
step='A'; // 切换到下一个玩家'A'。
}
}
// 检查第一种胜利情况:对角线(从左上到右下)。
if(game[0][2] == game[2][0] && game[1][1] == game[2][0]){
// 如果对角线上的棋子都是'X',则玩家'A'胜利。
if(game[0][2] == 'X')
return "A";
// 如果对角线上的棋子都是'O',则玩家'B'胜利。
else if(game[0][2] == 'O')
return "B";
}
// 检查第二种胜利情况:对角线(从右上到左下)。
if(game[0][0] == game[1][1] && game[1][1] == game[2][2]){
// 如果对角线上的棋子都是'X',则玩家'A'胜利。
if(game[0][0] == 'X')
return "A";
// 如果对角线上的棋子都是'O',则玩家'B'胜利。
else if(game[0][0] == 'O')
return "B";
}
// 检查行和列是否有连续的三个相同棋子。
for(int i =0;i<3;i++){
int countXA = 0; // 玩家'A'在当前行的'X'的数量。
int countXB = 0; // 玩家'B'在当前行的'O'的数量。
int countYA = 0; // 玩家'A'在当前列的'X'的数量。
int countYB = 0; // 玩家'B'在当前列的'O'的数量。
for(int j=0;j<3;j++){
// 统计当前行和列上'X'和'O'的数量。
if(game[i][j] == 'X')
countXA++;
if(game[i][j] == 'O')
countXB++;
if(game[j][i] == 'X')
countYA++;
if(game[j][i] == 'O')
countYB++;
// 如果某一行或列上有三个连续的'X',则玩家'A'胜利。
if(countXA==3 || countYA==3)
return "A";
// 如果某一行或列上有三个连续的'O',则玩家'B'胜利。
if(countXB==3 || countYB==3)
return "B";
}
}
// 如果所有棋子都已经下完(即moves.length == 9),则游戏平局。
if(moves.length == 9)
return "Draw";
// 如果游戏还没有结束(即moves.length < 9),则游戏仍在进行中。
else
return "Pending";
}
}
17.困于环中的机器人
题目描述:
在无限的平面上,机器人最初位于 (0, 0)
处,面朝北方。注意:
- 北方向 是y轴的正方向。
- 南方向 是y轴的负方向。
- 东方向 是x轴的正方向。
- 西方向 是x轴的负方向。
机器人可以接受下列三条指令之一:
"G"
:直走 1 个单位"L"
:左转 90 度"R"
:右转 90 度
机器人按顺序执行指令 instructions
,并一直重复它们。
只有在平面中存在环使得机器人永远无法离开时,返回 true
。否则,返回 false
。
17.1解法一:
class Solution {
public boolean isRobotBounded(String instructions) {
// 初始化机器人的位置为原点
int axisX = 0; // X轴坐标
int axisY = 0; // Y轴坐标
// 定义方向的数组,0代表向东,1代表向北,2代表向西,3代表向南
String[] directions = {"E", "N", "W", "S"};
// 当前方向索引,初始化为0,即向东
int dirIndex = 0;
// 遍历指令数组
for (char instruction : instructions.toCharArray()) {
switch (instruction) {
case 'G':
// 前进指令
// 根据当前方向移动机器人
switch (dirIndex) {
case 0: axisX++; break; // 向东移动
case 1: axisY++; break; // 向北移动
case 2: axisX--; break; // 向西移动
case 3: axisY--; break; // 向南移动
}
break;
case 'L':
// 左转指令
// 左转90度,即当前方向索引减1,若小于0则回到最后一个方向
dirIndex = (dirIndex + 3) % 4;
break;
case 'R':
// 右转指令
// 右转90度,即当前方向索引加1,若超过3则回到第一个方向
dirIndex = (dirIndex + 1) % 4;
break;
}
}
// 判断机器人是否回到原点或者至少旋转了一次
// 如果回到原点或者至少旋转了一次,则认为机器人是有界的
return (axisX == 0 && axisY == 0) || dirIndex != 0;
}
}
17.2解法二:
class Solution {
public boolean isRobotBounded(String instructions) {
// 初始化机器人在坐标轴上的位置,原点为(0, 0)
int axisX = 0; // X轴坐标
int axisY = 0; // Y轴坐标
// 定义所有可能的移动方向,分别对应北、东、南、西四个方向
String[] allDirection = {"axisY","-axisX","-axisY","axisX"};
// 初始化当前移动方向为北方向
String direction = "axisY";
int i = 0;
// 遍历指令字符串中的每个字符
for (char ch : instructions.toCharArray()) {
switch (ch) {
// 左转指令
case 'L':
// 更新方向索引,若超出范围则回到数组开头
if (++i > allDirection.length - 1) i = 0;
// 设置新的方向
direction = allDirection[i];
break;
// 右转指令
case 'R':
// 更新方向索引,若小于0则回到数组末尾
if (--i < 0) i = allDirection.length - 1;
// 设置新的方向
direction = allDirection[i];
break;
// 前进指令
case 'G':
// 根据当前方向更新机器人的位置
switch (direction) {
// 如果当前方向是北,则Y轴坐标加1
case "axisY":
axisY++;
break;
// 如果当前方向是西,则X轴坐标减1
case "-axisX":
axisX--;
break;
// 如果当前方向是南,则Y轴坐标减1
case "-axisY":
axisY--;
break;
// 如果当前方向是东,则X轴坐标加1
case "axisX":
axisX++;
break;
}
break;
}
}
// 判断机器人是否回到原点或方向发生了改变
return (axisX == 0 && axisY == 0) || !direction.equals("axisY");
}
}
18.最富有客户的资产总量
题目描述:
给你一个 m x n
的整数网格 accounts
,其中 accounts[i][j]
是第 i
位客户在第 j
家银行托管的资产数量。返回最富有客户所拥有的 资产总量 。
客户的 资产总量 就是他们在各家银行托管的资产数量之和。最富有客户就是 资产总量 最大的客户。
18.1解法一:
// 定义一个名为Solution的类
class Solution {
// 定义一个公共方法maximumWealth,该方法接收一个二维整数数组accounts作为参数
public int maximumWealth(int[][] accounts) {
// 初始化一个变量maxResource,用于存储最大的财富值,初始值为0
int maxResource = 0;
// 使用外层循环遍历accounts数组中的每个账户
for(int i=0; i<accounts.length; i++){
// 初始化一个变量resource,用于存储当前账户的财富总和,初始值为0
int resource = 0;
// 使用内层循环遍历当前账户中的每个元素(即每个存款)
for(int j=0; j<accounts[i].length; j++){
// 将当前存款累加到resource中
resource += accounts[i][j];
}
// 如果当前账户的财富总和resource大于maxResource,则更新maxResource的值
if(resource > maxResource)
maxResource = resource;
}
// 返回最大的财富值
return maxResource;
}
}
19.矩阵对角线元素的和
题目描述:
给你一个正方形矩阵 mat
,请你返回矩阵对角线元素的和。
请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。
19.1解法一:
// 定义一个名为Solution的类
class Solution {
// 定义一个公共方法diagonalSum,该方法接收一个二维整数数组mat作为参数
public int diagonalSum(int[][] mat) {
// 初始化变量primaryDiagonal,用于存储主对角线上的元素和
int primaryDiagonal = 0;
// 初始化变量secondaryDiagonal,用于存储副对角线上的元素和
int secondaryDiagonal = 0;
// 使用两个嵌套的for循环遍历二维数组mat中的每个元素
for(int i = 0; i < mat.length; i++){
for(int j = 0; j < mat[i].length; j++){
// 如果当前元素的行索引i等于列索引j,则它是主对角线上的元素
if(i == j){
// 将主对角线上的元素累加到primaryDiagonal中
primaryDiagonal += mat[i][j];
}
// 如果当前元素的行索引i加上矩阵长度减1等于列索引j,则它是副对角线上的元素
if(mat.length - 1 - i == j){
// 将副对角线上的元素累加到secondaryDiagonal中
secondaryDiagonal += mat[i][j];
}
}
}
// 检查矩阵的长度是否为偶数
if(mat.length % 2 == 0){
// 如果矩阵长度是偶数,则直接返回主对角线和副对角线的元素和
return primaryDiagonal + secondaryDiagonal;
} else {
// 如果矩阵长度是奇数,则需要从结果中减去位于矩阵中心的元素(只计算一次)
// 因为在累加过程中,该元素被计算了两次(一次在主对角线上,一次在副对角线上)
return primaryDiagonal + secondaryDiagonal - mat[mat.length / 2][mat.length / 2];
}
}
}
19.2解法二:
// 定义一个名为Solution的类
class Solution {
// 定义一个公共方法diagonalSum,该方法接收一个二维整数数组mat作为参数,并返回对角线上元素的和
public int diagonalSum(int[][] mat) {
// 初始化变量diagonalSum,用于累加对角线上的元素值
int diagonalSum = 0;
// 外层循环遍历二维数组mat的每一行
for(int i = 0; i < mat.length; i++){
// 内层循环遍历当前行的每一列
for(int j = 0; j < mat[i].length; j++){
// 判断当前元素是否位于主对角线上(即行索引i等于列索引j)
if(i == j){
// 如果是,将当前元素值加到diagonalSum上
diagonalSum += mat[i][j];
}
// 判断当前元素是否位于副对角线上(即行索引i与列索引j之和等于矩阵的边长减1)
// 注意这里使用mat.length - 1 - i,因为副对角线从矩阵的右上角开始,行索引递减
else if(mat.length - 1 - i == j){
// 如果是,同样将当前元素值加到diagonalSum上
diagonalSum += mat[i][j];
}
}
}
// 返回对角线上元素的总和
return diagonalSum;
}
}
20. 螺旋矩阵
题目描述:
给你一个 m
行 n
列的矩阵 matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
20.1解法一:
import java.util.ArrayList;
import java.util.List;
// 定义一个名为Solution的类
class Solution {
// 定义一个公共方法spiralOrder,该方法接收一个二维整数数组matrix作为参数
// 并返回一个包含按螺旋顺序遍历的元素的List<Integer>
public List<Integer> spiralOrder(int[][] matrix) {
// 创建一个ArrayList来存储按螺旋顺序遍历的元素
List<Integer> result = new ArrayList<>();
// 如果矩阵为空,直接返回空列表
if (matrix == null || matrix.length == 0) {
return result;
}
// 初始化四个边界:上边界、下边界、左边界、右边界
int top = 0, bottom = matrix.length - 1, left = 0, right = matrix[0].length - 1;
// 当上下边界没有交错(即还在矩阵范围内)时,继续遍历
while (top <= bottom && left <= right) {
// 从左到右遍历上边界
for (int i = left; i <= right; i++) {
result.add(matrix[top][i]);
}
// 上边界下移
top++;
// 从上到下遍历右边界
for (int i = top; i <= bottom; i++) {
result.add(matrix[i][right]);
}
// 右边界左移
right--;
// 如果上下边界没有交错,则继续遍历下边界和左边界
if (top <= bottom) {
// 从右到左遍历下边界
for (int i = right; i >= left; i--) {
result.add(matrix[bottom][i]);
}
// 下边界上移
bottom--;
}
if (left <= right) {
// 从下到上遍历左边界
for (int i = bottom; i >= top; i--) {
result.add(matrix[i][left]);
}
// 左边界右移
left++;
}
}
// 返回按螺旋顺序遍历的元素列表
return result;
}
}
21. 矩阵置零
给定一个 m x n
的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。
21.1解法一:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
class Solution {
// 将二维整数矩阵matrix中所有0元素所在的行和列都置为0
public void setZeroes(int[][] matrix) {
// 使用两个列表分别记录0元素所在的行索引和列索引
List<Integer> listX = new ArrayList<>();
List<Integer> listY = new ArrayList<>();
// 遍历矩阵的每一个元素
for(int i = 0; i < matrix.length; i++){
for(int j = 0; j < matrix[i].length; j++){
// 如果当前元素为0,则记录其行索引和列索引
if(matrix[i][j] == 0){
listX.add(i);
listY.add(j);
}
}
}
// 使用迭代器遍历列索引列表,并将对应列的所有元素置为0
Iterator<Integer> itY = listY.iterator();
while (itY.hasNext()){
Integer Y = (Integer) itY.next();
for(int i = 0; i < matrix.length; i++){
matrix[i][Y] = 0;
}
}
// 使用迭代器遍历行索引列表,并将对应行的所有元素置为0
Iterator<Integer> itX = listX.iterator();
while (itX.hasNext()){
Integer X = (Integer) itX.next();
for(int j = 0; j < matrix[X].length; j++){
matrix[X][j] = 0;
}
}
}
}
22.在区间范围内统计奇数数目
题目描述:
给你两个非负整数 low
和 high
。请你返回 low
和 high
之间(包括二者)奇数的数目。
22.1解法一:
class Solution {
public int countOdds(int low, int high) {
// 如果 low 和 high 都是偶数,或者它们都是奇数,则范围内的奇数数量是 (high - low) / 2 + (low % 2 == 1 ? 1 : 0)
// 如果 low 是偶数且 high 是奇数,或者 low 是奇数且 high 是偶数,则范围内的奇数数量是 (high - low) / 2 + 1
// 可以通过异或操作检查 low 和 high 的奇偶性是否不同
int count = (high - low) / 2; // 计算范围内每两个数中奇数的数量(因为每两个连续的数中有一个奇数)
// 如果 low 和 high 的奇偶性不同,或者 low 是奇数,则需要加上额外的 1
if ((low % 2 != 0) || (low % 2 != high % 2)) {
count++;
}
return count;
}
}
22.2解法二:
class Solution {
// 定义一个公共方法 countOdds,接收两个整数参数 low 和 high
public int countOdds(int low, int high) {
// 如果 high 和 low 都是奇数(即除以 2 的余数都是 1)
if(high % 2 == 1 && low % 2 == 1) {
// 返回 (high - low) 除以 2 的商加 1
// 这是因为 high 和 low 都是奇数,所以范围内的奇数数量是偶数数量加 1
return (high - low) / 2 + 1;
} else if(high % 2 == 0 && low % 2 == 0) {
// 如果 high 和 low 都是偶数(即除以 2 的余数是 0)
// 返回 (high - low) 除以 2 的商
// 这是因为 high 和 low 都是偶数,所以范围内的奇数数量就是偶数数量
return (high - low) / 2;
} else {
// 如果 high 和 low 的奇偶性不同
// 返回 (high - low + 1) 除以 2 的商
// 这是因为无论 high 和 low 哪个是奇数,范围内的奇数数量都是偶数数量加 1
// 加 1 是为了确保当 high 和 low 相邻且一个是奇数、一个是偶数时,奇数数量计算正确
return (high - low + 1) / 2;
}
}
}
23.去掉最低工资和最高工资后的工资平均值
题目描述:
给你一个整数数组 salary
,数组里每个数都是 唯一 的,其中 salary[i]
是第 i
个员工的工资。
请你返回去掉最低工资和最高工资以后,剩下员工工资的平均值。
23.1解法一:
// 定义一个名为Solution的类
class Solution {
// 定义一个名为average的公共方法,它接受一个整数数组salary作为参数,并返回一个double类型的值
public double average(int[] salary) {
// 初始化最大薪资为数组的第一个元素
int maxSalary = salary[0];
// 初始化最小薪资为数组的第一个元素
int minSalary = salary[0];
// 初始化薪资总和为0
int sumSalary = 0;
// 遍历数组中的每一个薪资
for(int i=0; i<salary.length; i++){
// 如果当前薪资大于最大薪资,则更新最大薪资
if(salary[i]>maxSalary)
maxSalary = salary[i];
// 如果当前薪资小于最小薪资,则更新最小薪资
if(salary[i]<minSalary)
minSalary = salary[i];
// 累加薪资到总和
sumSalary += salary[i];
}
// 返回去掉最高和最低薪资后的平均薪资。这里先转换为double类型以进行浮点数除法
return (double) (sumSalary - minSalary - maxSalary) / (salary.length - 2);
}
}
23.2解法二:
// 导入Java的工具类,用于操作数组等
import java.util.Arrays;
// 定义一个名为Solution的类
class Solution {
// 定义一个公共方法average,接受一个整数数组salary作为参数,返回平均薪资的double值
public double average(int[] salary) {
// 初始化最大薪资为数组的第一个元素
int maxSalary = salary[0];
// 初始化最小薪资为数组的第一个元素
int minSalary = salary[0];
// 初始化薪资总和为0
int sumSalary = 0;
// 遍历salary数组
for(int i = 0; i < salary.length; i++){
// 使用Math.max方法比较当前薪资和最大薪资,更新最大薪资
maxSalary = Math.max(salary[i], maxSalary);
// 使用Math.min方法比较当前薪资和最小薪资,更新最小薪资
minSalary = Math.min(salary[i], minSalary);
// 累加当前薪资到薪资总和
sumSalary += salary[i];
}
// 返回去掉最高和最低薪资后的平均薪资
// 薪资总和减去最大和最小薪资,再除以(数组长度 - 2),确保去除最高和最低薪资后的平均
// 注意:这里需要将结果转换为double类型,以进行浮点数除法
return (double) (sumSalary - minSalary - maxSalary) / (salary.length - 2);
}
}
23.3解法三:
import java.util.Arrays; // 导入Arrays类,用于操作数组
import java.util.OptionalInt; // 导入OptionalInt类,用于表示可能存在的int值
class Solution {
public double average(int[] salary) {
// 使用流API查找salary数组中的最大值,并将其封装在OptionalInt中
OptionalInt maxSalary = Arrays.stream(salary).max();
// 使用流API查找salary数组中的最小值,并将其封装在OptionalInt中
OptionalInt minSalary = Arrays.stream(salary).min();
// 使用流API计算salary数组中所有元素的总和
int sumSalary = Arrays.stream(salary).sum();
// 计算去掉最高和最低薪资后的平均薪资
// 注意:这里应该是从总和中减去最大薪资和最小薪资,然后除以(salary.length - 2)
// 但由于max()和min()方法返回的是OptionalInt,我们需要使用getAsInt()来获取实际的int值
return (double) (sumSalary - maxSalary.getAsInt() - minSalary.getAsInt()) / (salary.length - 2);
}
}
24.柠檬水找零
题目描述:
在柠檬水摊上,每一杯柠檬水的售价为 5
美元。顾客排队购买你的产品,(按账单 bills
支付的顺序)一次购买一杯。
每位顾客只买一杯柠檬水,然后向你付 5
美元、10
美元或 20
美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5
美元。
注意,一开始你手头没有任何零钱。
给你一个整数数组 bills
,其中 bills[i]
是第 i
位顾客付的账。如果你能给每位顾客正确找零,返回 true
,否则返回 false
。
24.1解法一:
class Solution {
// lemonadeChange方法接收一个整数数组bills,其中每个元素代表顾客支付的金额
public boolean lemonadeChange(int[] bills) {
// count5用于跟踪摊位上5美元纸币的数量
int count5 = 0;
// count10用于跟踪摊位上10美元纸币的数量
int count10 = 0;
// 遍历顾客支付的金额数组
for(int money : bills){
// 根据顾客支付的金额进行处理
switch (money){
// 如果顾客支付了5美元
case 5:
// 摊位的5美元纸币数量增加
count5++;
break;
// 如果顾客支付了10美元
case 10:
// 检查是否有足够的5美元纸币来换取10美元
if(count5 > 0){
// 如果有,减少一个5美元纸币并增加一个10美元纸币
count5--;
count10++;
}
// 如果没有足够的5美元纸币,返回false表示无法换取零钱
else
return false;
break;
// 如果顾客支付了20美元
case 20:
// 首先检查是否有足够的10美元和5美元纸币来换取20美元
if(count10 > 0 && count5 > 0){
// 如果有,减少一个10美元纸币和一个5美元纸币
count5--;
count10--;
}
// 如果没有足够的10美元和5美元纸币,检查是否有至少3个5美元纸币
else if(count5 > 2){
// 如果有,减少3个5美元纸币
count5 -= 3;
}
// 如果既没有足够的10美元和5美元纸币,也没有至少3个5美元纸币,返回false
else
return false;
}
}
// 如果所有顾客都能得到零钱,返回true
return true;
}
}
25.三角形的最大周长
题目描述:
给定由一些正数(代表长度)组成的数组 nums
,返回 由其中三个长度组成的、面积不为零的三角形的最大周长 。如果不能形成任何面积不为零的三角形,返回 0
。
25.1解法一:
import java.util.Arrays; // 导入Java的Arrays类,用于数组操作
class Solution { // 定义一个名为Solution的类
public int largestPerimeter(int[] nums) { // 定义一个公共方法,名为largestPerimeter,它接受一个整数数组作为参数
Arrays.sort(nums); // 使用Arrays类的sort方法对传入的数组进行升序排序
// 从数组的倒数第三个元素开始遍历(因为最大的三个数一定在排序后的数组的末尾)
for(int i=nums.length-1; i>=2; i--){
// 检查当前元素(最长的边)是否小于其余两条边的和(即,是否能形成一个三角形)
if(nums[i-1] + nums[i-2] > nums[i]){
// 如果能形成三角形,返回这三条边的和,即三角形的周长
return nums[i-1] + nums[i-2] + nums[i];
}
}
// 如果不能形成任何面积不为零的三角形,返回0
return 0;
}
}
26. 缀点成线
给定一个数组 coordinates
,其中 coordinates[i] = [x, y]
, [x, y]
表示横坐标为 x
、纵坐标为 y
的点。请你来判断,这些点是否在该坐标系中属于同一条直线上。
26.1解法一:
class Solution {
// 检查给定的坐标点是否都在同一条直线上
public boolean checkStraightLine(int[][] coordinates) {
// 至少需要两个点来确定一条直线
if (coordinates.length < 2) {
return false;
}
// 使用第一个点和第二个点来确定直线的斜率
int slopeX = coordinates[1][0] - coordinates[0][0];
int slopeY = coordinates[1][1] - coordinates[0][1];
// 遍历所有其他点,检查它们是否满足同一条直线的条件
for (int i = 2; i < coordinates.length; i++) {
int currentX = coordinates[i][0] - coordinates[0][0];
int currentY = coordinates[i][1] - coordinates[0][1];
// 如果当前点的斜率与直线斜率不同,则它们不在同一条直线上
if (slopeX * currentY != slopeY * currentX) {
return false;
}
}
// 如果所有点都满足条件,则它们都在同一条直线上
return true;
}
}
27.二进制求和
题目描述:
给你两个二进制字符串 a
和 b
,以二进制字符串的形式返回它们的和。
27.1解法一:
class Solution {
public String addBinary(String a, String b) {
StringBuilder ans = new StringBuilder();
int carry = 0;
for (int i = a.length() - 1, j = b.length() - 1; i >= 0 || j >= 0; i--, j--) {
int sum = carry;
sum += i >= 0 ? a.charAt(i) - '0' : 0; // 如果 i 有效,则加上 a 的当前位,否则加上0
sum += j >= 0 ? b.charAt(j) - '0' : 0; // 如果 j 有效,则加上 b 的当前位,否则加上0
ans.append(sum % 2); // 将当前位的和模2的结果追加到ans中,这将是当前位的值
carry = sum / 2; // 更新进位为当前位的和除以2的结果
}
if (carry == 1) { // 如果最高位有进位,则将其追加到ans中
ans.append(carry);
}
return ans.reverse().toString(); // 由于ans是从右到左构建的,因此需要反转它以获得正确的从左到右的顺序
}
}
作者:画手大鹏
链接:https://leetcode.cn/problems/add-binary/solutions/9617/hua-jie-suan-fa-67-er-jin-zhi-qiu-he-by-guanpengch/
来源:力扣(LeetCode)
28.字符串相乘
给定两个以字符串形式表示的非负整数 num1
和 num2
,返回 num1
和 num2
的乘积,它们的乘积也表示为字符串形式。
28.1解法一:
class Solution {
public String multiply(String num1, String num2) {
if (num1.equals("0") || num2.equals("0")) {
return "0";
}
String ans = "0";
int m = num1.length(), n = num2.length();
for (int i = n - 1; i >= 0; i--) {
StringBuffer curr = new StringBuffer();
int add = 0;
for (int j = n - 1; j > i; j--) {
curr.append(0);
}
int y = num2.charAt(i) - '0';
for (int j = m - 1; j >= 0; j--) {
int x = num1.charAt(j) - '0';
int product = x * y + add;
curr.append(product % 10);
add = product / 10;
}
if (add != 0) {
curr.append(add % 10);
}
ans = addStrings(ans, curr.reverse().toString());
}
return ans;
}
public String addStrings(String num1, String num2) {
int i = num1.length() - 1, j = num2.length() - 1, add = 0;
StringBuffer ans = new StringBuffer();
while (i >= 0 || j >= 0 || add != 0) {
int x = i >= 0 ? num1.charAt(i) - '0' : 0;
int y = j >= 0 ? num2.charAt(j) - '0' : 0;
int result = x + y + add;
ans.append(result % 10);
add = result / 10;
i--;
j--;
}
ans.reverse();
return ans.toString();
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/multiply-strings/solutions/372098/zi-fu-chuan-xiang-cheng-by-leetcode-solution/
来源:力扣(LeetCode)
28.2解法二:
class Solution {
/**
* 计算形式
* num1
* x num2
* ------
* result
*/
public String multiply(String num1, String num2) {
if (num1.equals("0") || num2.equals("0")) {
return "0";
}
// 保存计算结果
String res = "0";
// num2 逐位与 num1 相乘
for (int i = num2.length() - 1; i >= 0; i--) {
int carry = 0;
// 保存 num2 第i位数字与 num1 相乘的结果
StringBuilder temp = new StringBuilder();
// 补 0
for (int j = 0; j < num2.length() - 1 - i; j++) {
temp.append(0);
}
int n2 = num2.charAt(i) - '0';
// num2 的第 i 位数字 n2 与 num1 相乘
for (int j = num1.length() - 1; j >= 0 || carry != 0; j--) {
int n1 = j < 0 ? 0 : num1.charAt(j) - '0';
int product = (n1 * n2 + carry) % 10;
temp.append(product);
carry = (n1 * n2 + carry) / 10;
}
// 将当前结果与新计算的结果求和作为新的结果
res = addStrings(res, temp.reverse().toString());
}
return res;
}
/**
* 对两个字符串数字进行相加,返回字符串形式的和
*/
public String addStrings(String num1, String num2) {
StringBuilder builder = new StringBuilder();
int carry = 0;
for (int i = num1.length() - 1, j = num2.length() - 1;
i >= 0 || j >= 0 || carry != 0;
i--, j--) {
int x = i < 0 ? 0 : num1.charAt(i) - '0';
int y = j < 0 ? 0 : num2.charAt(j) - '0';
int sum = (x + y + carry) % 10;
builder.append(sum);
carry = (x + y + carry) / 10;
}
return builder.reverse().toString();
}
}
作者:breezean
链接:https://leetcode.cn/problems/multiply-strings/solutions/
来源:力扣(LeetCode)
29 pow(x,n)
实现 pow(x, n) ,即计算 x
的整数 n
次幂函数(即, )。
class Solution {
public double myPow(double x, int n) {
return Math.pow(x,n);
}
}
32.两数相加
题目描述:给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummyHead = new ListNode(0);
ListNode current = dummyHead;
int carry = 0;
// 当两个链表都不为空或者还有进位时,继续处理
while (l1 != null || l2 != null || carry != 0) {
int sum = carry; // 先将进位加到和中
if (l1 != null) {
sum += l1.val;
l1 = l1.next;
}
if (l2 != null) {
sum += l2.val;
l2 = l2.next;
}
carry = sum / 10; // 计算新的进位
current.next = new ListNode(sum % 10); // 创建新节点,值为sum的个位数
current = current.next; // 移动当前节点到新节点
}
return dummyHead.next; // 返回dummyHead的下一个节点,即结果链表的头节点
}
}
33.两数相加2
题目描述:
给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
题解:
class Solution {
// 反转链表 helper 函数
public ListNode reverseList(ListNode head){
ListNode pre = null, cur = head;
while(cur != null){
ListNode temp = cur.next; // 临时节点,保存下一个节点
cur.next = pre; // 反转当前节点的指针
pre = cur; // pre 移动到当前节点
cur = temp; // cur 移动到下一个节点
}
return pre; // 返回反转后的头节点
}
// 主函数,用于相加两个链表
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
// 先反转两个链表
l1 = reverseList(l1);
l2 = reverseList(l2);
// 调用 addTwo 函数进行相加
ListNode l3 = addTwo(l1, l2);
// 反转结果链表并返回
return reverseList(l3);
}
// 实际进行链表相加的函数
public ListNode addTwo(ListNode l1, ListNode l2){
ListNode dummy = new ListNode(0); // 创建哑结点
ListNode cur = dummy; // 当前节点指针,用于构建结果链表
int carry = 0; // 初始化进位为0
while(l1 != null || l2 != null || carry != 0){ // 当两个链表中任一链表还有节点或者还有进位时,继续执行
int sum = carry; // 当前和先等于进位
if(l1 != null){ // 如果 l1 不为空,加上 l1 的值
sum += l1.val;
l1 = l1.next; // l1 移动到下一个节点
}
if(l2 != null){ // 如果 l2 不为空,加上 l2 的值
sum += l2.val;
l2 = l2.next; // l2 移动到下一个节点
}
carry = sum / 10; // 计算新的进位
cur.next = new ListNode(sum % 10); // 创建新节点,值为sum的个位数
cur = cur.next; // 移动当前节点到新节点
}
return dummy.next; // 返回哑结点的下一个节点,即结果链表的头节点
}
}