1.字符串相乘
第一种方法,直接暴力手撕算法:
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();
}
}
解法2:
该算法是通过两数相乘时,乘数某位与被乘数某位相乘,与产生结果的位置的规律来完成。具体规律如下:
乘数 num1 位数为 M,被乘数 num2 位数为 N, num1 x num2 结果 res 最大总位数为 M+N
num1[i] x num2[j] 的结果为 tmp(位数为两位,"0x", "xy" 的形式),其第一位位于 res[i+j],第二位位于 res[i+j+1]。
class Solution {
public String multiply(String num1, String num2) {
if (num1.equals("0") || num2.equals("0")) {
return "0";
}
int m = num1.length(), n = num2.length();
int[] ansArr = new int[m + n];
for (int i = m - 1; i >= 0; i--) {
int x = num1.charAt(i) - '0';
for (int j = n - 1; j >= 0; j--) {
int y = num2.charAt(j) - '0';
ansArr[i + j + 1] += x * y;
}
}
for (int i = m + n - 1; i > 0; i--) {
ansArr[i - 1] += ansArr[i] / 10;
ansArr[i] %= 10;
}
int index = ansArr[0] == 0 ? 1 : 0;
StringBuffer ans = new StringBuffer();
while (index < m + n) {
ans.append(ansArr[index]);
index++;
}
return ans.toString();
}
}
2.最小覆盖子串
4、对于新加入的字符s[i],如果hs[s[i]] <= ht[s[i]],说明当前新加入的字符s[i]是必需的,且还未到达字符串t所要求的数量。我们还需要事先定义一个cnt变量, cnt维护的是s字符串[j,i]区间中满足t字符串的元素的个数,记录相对应字符的总数。新加入的字符s[i]必需,则cnt++。
5、我们向右扩展滑动窗口的同时也不能忘记收缩滑动窗口。因此当hs[s[j]] > ht[s[j]时,说明hs哈希表中s[j]的数量多于ht哈希表中s[j]的数量,此时我们就需要向右收缩滑动窗口,j++并使hs[s[j]]--,即hs[s[j ++ ]] --。
6、当cnt == t.size时,说明此时滑动窗口包含符串 t 的全部字符。我们重复上述过程找到最小窗口即为答案。
class Solution {
public String minWindow(String s, String t) {
//维护s串中滑动窗口中各个字符出现次数
Map<Character, Integer> hs = new HashMap<>();
//维护t串中各个字符出现次数
Map<Character, Integer> ht = new HashMap<>();
for (int i = 0; i < t.length(); i++) {
ht.put(t.charAt(i), ht.getOrDefault(t.charAt(i), 0)+1);
}
String ans="";
//cnt维护s串[left,right]中满足t串的元素的个数,记录相对应字符的总数
int len=Integer.MAX_VALUE,cnt=0;
//区间[left,right]表示当前滑动窗口
for (int left=0,right = 0; right < s.length(); right++) {
hs.put(s.charAt(right), hs.getOrDefault(s.charAt(right), 0)+1);
//如果ht表中也包含当前字符
if (ht.containsKey(s.charAt(right))) {
//并且hs表中的字符个数<=ht表中的字符个数,说明该字符是必须的,并且还未到达字符串t所要求的数量
if (hs.get(s.charAt(right))<=ht.get(s.charAt(right))) {
cnt++;
}
}
//收缩滑动窗口
//如果左边界的值不在ht表中 或者 它在hs表中的出现次数多于ht表中的出现次数
while(left < right && (!ht.containsKey(s.charAt(left)) || hs.get(s.charAt(left)) > ht.get(s.charAt(left)))){
hs.put(s.charAt(left),hs.get(s.charAt(left)) - 1);
left++;
}
//此时滑动窗口包含符串 t 的全部字符
if (cnt==t.length()&&right-left+1<len) {
len=right-left+1;
ans=s.substring(left,right+1);
}
}
return ans;
}
}
3.分隔链表
根据题意,考虑通过「新建两个链表」实现原链表分割,算法流程为:
- 新建两个链表 sml_dummy , big_dummy ,分别用于添加所有「节点值 <x 」、「节点值 ≥x 」的节点。
- 遍历链表 head 并依次比较各节点值 head.val 和 x 的大小:
- 若 head.val < x ,则将节点 head 添加至链表 sml_dummy 最后面;
- 若 head.val >= x ,则将节点 head 添加至链表 big_dummy 最后面;
- 遍历完成后,拼接 sml_dummy 和 big_dummy 链表。
- 最终返回头节点 sml_dummy.next 即可。
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode smlDummy = new ListNode(0), bigDummy = new ListNode(0);
ListNode sml = smlDummy, big = bigDummy;
while (head != null) {
if (head.val < x) {
sml.next = head;
sml = sml.next;
} else {
big.next = head;
big = big.next;
}
head = head.next;
}
sml.next = bigDummy.next;
big.next = null;
return smlDummy.next;
}
}