1.乘积最大子数组
解题思路:
- 标签:动态规划
- 遍历数组时计算当前最大值,不断更新
- 令imax为当前最大值,则当前最大值为 imax = max(imax * nums[i], nums[i])
- 由于存在负数,那么会导致最大的变最小的,最小的变最大的。因此还需要维护当前最小值imin,imin = min(imin * nums[i], nums[i])
- 当负数出现时则imax与imin进行交换再进行下一步计算
- 时间复杂度:O(n)
class Solution {
public int maxProduct(int[] nums) {
int max =Integer.MIN_VALUE,imax=1,imin=1;
for(int i =0;i<nums.length;i++){
if(nums[i]<0){
int tmp =imax;
imax =imin;
imin =tmp;
}
imax =Math.max(imax*nums[i],nums[i]);
imin =Math.min(imin*nums[i],nums[i]);
max =Math.max(max,imax);
}
return max;
}
}
2.最小栈
解题思路:
要实现一个 stack,那么我们还能用 java 自带的 stack 吗?也不用纠结,这道题的关键其实是实现「得到最小值这个功能」,所以为了代码简洁些,我们就直接使用系统自带的 stack 了。
这道题最直接的解法就是我们可以用两个栈,一个栈去保存正常的入栈出栈的值,另一个栈去存最小值,也就是用栈顶保存当前所有元素的最小值。存最小值的栈的具体操作流程如下:
- 将第一个元素入栈。
- 新加入的元素如果大于栈顶元素,那么新加入的元素就不处理。
- 新加入的元素如果小于等于栈顶元素,那么就将新元素入栈。
- 出栈元素不等于栈顶元素,不操作。
- 出栈元素等于栈顶元素,那么就将栈顶元素出栈。
入栈 3
| | | |
| | | |
|_3_| |_3_|
stack minStack
入栈 5 , 5 大于 minStack 栈顶,不处理
| | | |
| 5 | | |
|_3_| |_3_|
stack minStack
入栈 2 ,此时右边的 minStack 栈顶就保存了当前最小值 2
| 2 | | |
| 5 | | 2 |
|_3_| |_3_|
stack minStack
出栈 2,此时右边的 minStack 栈顶就保存了当前最小值 3
| | | |
| 5 | | |
|_3_| |_3_|
stack minStack
出栈 5,右边 minStack 不处理
| | | |
| | | |
|_3_| |_3_|
stack minStack
出栈 3
| | | |
| | | |
|_ _| |_ _|
stack minStack
举个例子:
class MinStack {
/** initialize your data structure here. */
private Stack<Integer> stack;
private Stack<Integer> minStack;
public MinStack() {
stack = new Stack<>();
minStack = new Stack<>();
}
public void push(int x) {
stack.push(x);
if (!minStack.isEmpty()) {
int top = minStack.peek();
//小于的时候才入栈
if (x <= top) {
minStack.push(x);
}
}else{
minStack.push(x);
}
}
public void pop() {
int pop = stack.pop();
int top = minStack.peek();
//等于的时候再出栈
if (pop == top) {
minStack.pop();
}
}
public int top() {
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}
3.分数到小数
解题思路:
首先可以明确,两个数相除要么是「有限位小数」,要么是「无限循环小数」,而不可能是「无限不循环小数」。
然后考虑人工计算两数相除是如何进行
这引导我们可以在模拟竖式计算(除法)过程中,使用「哈希表」记录某个余数最早在什么位置出现过,一旦出现相同余数,则将「出现位置」到「当前结尾」之间的字符串抠出来,即是「循环小数」部分。
class Solution {
public String fractionToDecimal(int numerator, int denominator) {
// 转 long 计算,防止溢出
long a = numerator, b = denominator;
// 如果本身能够整除,直接返回计算结果
if (a % b == 0) return String.valueOf(a / b);
StringBuilder sb = new StringBuilder();
// 如果其一为负数,先追加负号
if (a * b < 0) sb.append('-');
a = Math.abs(a); b = Math.abs(b);
// 计算小数点前的部分,并将余数赋值给 a
sb.append(String.valueOf(a / b) + ".");
a %= b;
Map<Long, Integer> map = new HashMap<>();
while (a != 0) {
// 记录当前余数所在答案的位置,并继续模拟除法运算
map.put(a, sb.length());
a *= 10;
sb.append(a / b);
a %= b;
// 如果当前余数之前出现过,则将 [出现位置 到 当前位置] 的部分抠出来(循环小数部分)
if (map.containsKey(a)) {
int u = map.get(a);
return String.format("%s(%s)", sb.substring(0, u), sb.substring(u));
}
}
return sb.toString();
}
}