leetcode刷题记录(784、371、953、917)

本文深入解析LeetCode上的三道算法题目:字符串大小写变化、无符号运算加法及外星字母排序验证,提供了详细的解题思路与代码实现。

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

2018.12.26 leetcode 刷题总结

题号:784

给定一个字符串S,通过将字符串S中的每个字母转变大小写,我们可以获得一个新的字符串。返回所有可能得到的字符串集合

示例:
输入: S = “a1b2”
输出: [“a1b2”, “a1B2”, “A1b2”, “A1B2”]
输入: S = “3z4”
输出: [“3z4”, “3Z4”]
输入: S = “12345”
输出: [“12345”]
注意:
S 的长度不超过12。
S 仅由数字和字母组成。

我的想法:

我只想到了穷举法,每个字母都有两种可能,在针对这两种可能,分别对应下一个字母的两种可能,以此类推,但是我没有写出程序
下面贴一下答案中大部分都在用的解法:

参考程序:

//java
class Solution {
    public List<String> letterCasePermutation(String S) {
		List<String> result = new ArrayList<>();
		getAllCombo(S.toCharArray(), 0, new StringBuilder(), result);
        
		return result;
    }
    // @params sChar: 所给字符串的字符数组
    // @params i: 字符数组的下标
    // @params sb: 用于存放新生成的字符串
    // @params result: 用于存放字符串的集合
    private void getAllCombo(char[] sChar, int i, StringBuilder sb, List<String> result) {
        // 递归出口
		if(i == sChar.length) {
			result.add(sb.toString());
			return;
		}
		
		char s = sChar[i];
        // 是字母分两种情况
		if((s >= 65 && s <= 90) || (s >= 97 && s <= 122)) {
			sb.append(String.valueOf(s).toLowerCase());
			getAllCombo(sChar, i+1, sb, result);
            sb.deleteCharAt(sb.length() - 1);
            
			sb.append(String.valueOf(s).toUpperCase());
			getAllCombo(sChar, i+1, sb, result);
            sb.deleteCharAt(sb.length() - 1);
        // 非字母直接append
		}else {
			sb.append(s);
			getAllCombo(sChar, i+1, sb, result);
            sb.deleteCharAt(sb.length() - 1);
		}
	}
}

上述程序中最重要的一步就是 sb.deleteCharAt(sb.length() - 1); 也就是在从递归函数出来之后,要删掉拼好的字符串的最后一位。为什么要这么做,首先考虑所给字符串中是含字母的情况,首先将字母转小写,由于递归函数的一个出口是拼接出了一种组合的情况,然后跳出当前函数,当跳出来的时候,StringBuilder已经是“满”的了,而跳出到上一层的时候,字符s还是StringBuilder的最后一位,因此我们要去掉拼接的最后一位,让这个字符s去变成大写(如果s是字母,若s是数字,执行完去掉最后一位的操作,会跳到上一层),继续拼出新的字符串,写入结果集合。总结一下上面的过程,就是先获得一个字母全小写的组合,然后从后至前,找出所有组合。

e.g. 字符串S = "a1b2"的遍历过程
获得a转小写,跳入,获得1,跳入,获得b转小写,跳入,获得2,跳入,得到a1b2,写入结果,跳出,删除最后一位,变成a1b,跳出,删除最后一位,变成a1(当前字符s=‘b’),向下执行转大写,变成a1B,跳入,获得2,变成a1B2,写入结果,跳出,删除最后一位,变成a1B,跳出,删除最后一位,变成a1,跳出,删除最后一位,变成a,跳出,删除最后一位,变成空,向下执行转大写,过程和上述过程相同。
当跳出函数时,当前的字符s始终是未删除最后一位的StringBuilder的最后一位

以上就是我自己的理解,大家可以自己debug一下看看执行过程,如果看完我写的东西之后更模糊了,(我自己都有点晕了)就忘了我写的这些吧(逃

题号:371

不使用运算符 + 和 - ​​​​​​​,计算两整数 ​​​​​​​a 、b ​​​​​​​之和。

我的想法:

位运算,直接看答案

参考程序:

// java
class Solution {
    public int getSum(int a, int b) {
        while (b!=0) {
            int tmp = a ^ b;
            b = (a & b) << 1;
            a = tmp;
        }
        return a;
    }
}

题号:953

某种外星语也使用英文小写字母,但可能顺序 order 不同。字母表的顺序(order)是一些小写字母的排列。
给定一组用外星语书写的单词 words,以及其字母表的顺序 order,只有当给定的单词在这种外星语中按字典序排列时,返回 true;否则,返回 false。

示例 1:
输入:words = [“hello”,“leetcode”], order = “hlabcdefgijkmnopqrstuvwxyz”
输出:true
解释:在该语言的字母表中,‘h’ 位于 ‘l’ 之前,所以单词序列是按字典序排列的。
示例 2:
输入:words = [“word”,“world”,“row”], order = “worldabcefghijkmnpqstuvxyz”
输出:false
解释:在该语言的字母表中,‘d’ 位于 ‘l’ 之后,那么 words[0] > words[1],因此单词序列不是按字典序排列的。
示例 3:
输入:words = [“apple”,“app”], order = “abcdefghijklmnopqrstuvwxyz”
输出:false
解释:当前三个字符 “app” 匹配时,第二个字符串相对短一些,然后根据词典编纂规则 “apple” > “app”,因为 ‘l’ > ‘∅’,其中 ‘∅’ 是空白字符,定义为比任何其他字符都小(更多信息)。

我的想法:

  1. 将给定的字母表中字母按顺序映射到正整数上,却靠前的值越大
  2. 遍历words数组,设立标志字符串,与下一个字符串相比较,将字符串变成字符数组,比较每一个字符,不满足直接返回false;若相同比较下一个字符;若满足,将与标志字符串相比较的字符串赋给标志字符串,与下一个字符串相比较
  3. 若遍历结束都没返回false,那么就返回true

对应程序:

// java
// 优化过的逻辑
class Solution {
    public boolean isAlienSorted(String[] words, String order) {
    	// 拿到字典
        Map<Character, Integer> dictionary = getDictionary(order);
        // 将第一个字符串设为标志位
        String flag = words[0];
        for(int i = 1; i < words.length; ++i) {
        	char[] fChars = flag.toCharArray();
        	char[] iChars =  words[i].toCharArray();
        	int fLength = fChars.length;
        	int iLength = iChars.length;
        	// 跳转标志
        	boolean jump = false;
        	
        	for(int j = 0; j < (fLength > iLength?iLength:fLength); ++j) {
        		int fNum = dictionary.get(fChars[j]);
        		int iNum = dictionary.get(iChars[j]);
        		if(fNum > iNum) {
        			// 跳转,去比较下一组
        			jump = true;
        			break;
        		}
        		
        		if(fNum < iNum) {
        			return false;
        		}
        	}
            
        	if(jump) {
        		jump = false;
        		flag = words[i];
        	}else {
        		return false;
        	}
        }
        
		return true;
    }
    // 映射字典
	private Map<Character, Integer> getDictionary(String order) {
		Map<Character, Integer> dictionary = new HashMap<>();
		int index = 26;
		for(char o : order.toCharArray()) {
			dictionary.put(o, index);
			index--;
		}
		
		return dictionary;
	}
}

提交记录里用时12ms和6ms的方法一模一样,连变量名都一样,emmmm

题号:917

给定一个字符串 S,返回 “反转后的” 字符串,其中不是字母的字符都保留在原地,而所有字母的位置发生反转。

示例 1:
输入:“ab-cd”
输出:“dc-ba”
示例 2:
输入:“a-bC-dEf-ghIj”
输出:“j-Ih-gfE-dCba”

我的想法:

  1. 读取源字符串的每个字符,若是英文字母,倒序存放;若是其他字符,将其下标和字符关系存到哈希表中
  2. 重组新的字符串,添加字母字符,当遇到下标为其他字符时,添加其他字符

对应程序:

// java
class Solution {
    public String reverseOnlyLetters(String S) {
    	// other<字符在字符数组中的索引值,字符>
		Map<Integer, Character> other = new HashMap<>();
		// 存放字母
		LinkedList<Character> letterList = new LinkedList<>();
		
		char[] SChar = S.toCharArray();
        for(int i = 0; i < SChar.length; ++i) {
        	// 若是字母,倒序放入
        	if((SChar[i] >= 'a' && SChar[i] <= 'z') || 
        			(SChar[i] >= 'A' && SChar[i] <= 'Z')) {
        		letterList.addFirst(SChar[i]);
        	}else {
        		// 其他字符,添加映射
        		other.put(i, SChar[i]);
        	}
        }
        
        StringBuilder sb = new StringBuilder();
        // letterList的索引
        int index = 0;
        for(int i = 0; i < S.length(); ++i) {
        	if(other.containsKey(i)) {
        		sb.append(other.get(i));
        	}else {
        		// 注意:不是letterList.get(i)
        		sb.append(letterList.get(index));
        		index++;
        	}
        }
        
        return sb.toString();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值