2019.1.8 leetcode 刷题总结
题号:806
我们要把给定的字符串 S 从左到右写到每一行上,每一行的最大宽度为100个单位,如果我们在写某个字母的时候会使这行超过了100 个单位,那么我们应该把这个字母写到下一行。我们给定了一个数组 widths ,这个数组 widths[0] 代表 ‘a’ 需要的单位, widths[1] 代表 ‘b’ 需要的单位,…, widths[25] 代表 ‘z’ 需要的单位。
现在回答两个问题:至少多少行能放下S,以及最后一行使用的宽度是多少个单位?将你的答案作为长度为2的整数列表返回。
示例 1:
输入:
widths = [10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10]
S = “abcdefghijklmnopqrstuvwxyz”
输出: [3, 60]
解释:
所有的字符拥有相同的占用单位10。所以书写所有的26个字母,
我们需要2个整行和占用60个单位的一行。
我的想法:
题目越长一定越简单,看清题目,widths数组就是对应“a-z”的,和字符串S无关;
首先需要一个变量flag来记录字符串S中的每个字符相加的和,一旦超过100,记录行数的变量line就要+1,flag就要等于当前字符对应的值,重复,直到遍历结束,由于是在遍历中记录的行数,因此遍历结束后行数应+1
对应程序:
// java
class Solution {
public int[] numberOfLines(int[] widths, String S) {
int[] res = new int[2];
int line = 0;
int flag = 0;
for(char s : S.toCharArray()) {
// 利用ASCII码值,和数组下标对应
flag += widths[s-97];
if(flag > 100) {
line++;
flag = widths[s-97];
}
}
res[0] = ++line;
res[1] = flag;
return res;
}
}
题号:349
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2]
示例 2:
输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [9,4]
我的想法:
双循环遍历两个数组,记录相同值,返回,这里就不贴代码了
优化
但双循环一定不是最好的方法,因此一般思路一定是降低循环的层数
程序:
// java
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> set1 = new HashSet<>();
Set<Integer> set2 = new HashSet<>();
// 用set1记录第一个数组中的值(去重)
for(int num : nums1) {
set1.add(num);
}
// 边遍历边判断
for(int num : nums2) {
if(set1.contains(num)) {
// 交集元素写入set2
set2.add(num);
}
}
// 这里用list来填充数组比set填充要快
List<Integer> temp = new ArrayList<>(set2);
int[] res = new int[set2.size()];
for(int i = 0; i < res.length; ++i) {
res[i] = temp.get(i);
}
return res;
}
}
题号:496
给定两个没有重复元素的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。找到 nums1 中每个元素在 nums2 中的下一个比其大的值。
nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出-1。
示例 1:
输入: nums1 = [4,1,2], nums2 = [1,3,4,2].
输出: [-1,3,-1]
解释:
对于num1中的数字4,你无法在第二个数组中找到下一个更大的数字,因此输出 -1。
对于num1中的数字1,第二个数组中数字1右边的下一个较大数字是 3。
对于num1中的数字2,第二个数组中没有下一个更大的数字,因此输出 -1。
我的想法:
以nums1中的4为例,遍历nums2,比较nums2中的每个元素是否与4相等,若相等,设立一个标志,比较后面的元素是否有大于4的,若有写入结果数组,若没有,写入-1。
对应程序:
// java
class Solution {
public static int[] nextGreaterElement1(int[] nums1, int[] nums2) {
int[] res = new int[nums1.length];
// nums1的下标
int index = 0;
// nums2的下标
int i = 0;
// 判断当前nums2中的元素是否再nums1[index]之后
boolean flag = false;
// 遍历nums1
while(index < nums1.length) {
int num1 = nums1[index];
int num2 = nums2[i];
if(num1 == num2) {
flag = true;
}
if(flag) {
// 进来下标先递增,直接比较nums2[i+1]和nums[index]
i++;
if(i == nums2.length) {
res[index] = -1;
}else {
if(nums2[i] > num1) {
res[index] = nums2[i];
}else {
continue;
}
}
// 若写入了结果的数组,值还原
if(res[index] != 0) {
flag = false;
i = 0;
index++;
continue;
}
}else {
// nums2元素下标递增,相当于遍历nums2
i++;
}
}
return res;
}
}
优化:
学到了一种数据结构:单调栈:
1.栈中元素保持从栈顶到栈底的单调性;
2.从栈顶到栈底,若元素逐渐增加,该栈称之为单调递增栈;若元素逐渐减小,该栈称之为单调递减栈。
针对该题,我们让给定的数组nums2中的元素入单调递增栈:若栈为空,元素直接入栈;若栈不为空,比较栈顶元素和要入栈的元素的大小,若栈顶元素大于要入栈的元素,该元素入栈,栈的单调性不会发生改变;若栈顶元素小于要入栈的元素,若元素入栈,栈的单调性会发生改变,因此不能入栈,也就是说,栈顶元素碰到了第一个在它这个之后比它大的元素,因此我们可以用映射表记录这对元素。因为要入栈的元素比栈顶元素大,因此栈顶元素出栈,让要入栈的元素入栈。
遍历nums2数组,循环上述过程。遍历结束后得到一个映射关系:key=元素,value=在key之后第一个比key大的元素。用nums1中的元素当作key取获得value即可。若没有映射,将-1存入结果数组即可
程序:
// java
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int[] res = new int[nums1.length];
LinkedList<Integer> stack = new LinkedList<>();// 单调递增栈
Map<Integer, Integer> map = new HashMap<>();
for(int num2 : nums2) {
if(stack.isEmpty() || stack.getFirst() > num2) {
stack.addFirst(num2);
}else {
while(!stack.isEmpty() && num2 > stack.getFirst()) {
map.put(stack.removeFirst(), num2);
}
stack.addFirst(num2);
}
}
for(int i = 0; i < res.length; ++i) {
if(map.get(nums1[i]) != null) {
res[i] = map.get(nums1[i]);
}else {
res[i] = -1;
}
}
return res;
}
}