leetcode刷题记录(806、349、496)

本文总结了LeetCode上的三道编程题的解题思路及优化方案,包括计算字符串占用的行数和宽度、求两数组交集以及寻找下一更大元素。通过实际案例,介绍了单调栈数据结构的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值