【LeetCode】Sama的个人记录_4

 

 

▊【Q17】(md) 电话号码的字母组合
 
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
 
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
 
示例:

  输入:“23”
  输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
说明:
  尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。
【LeetCode】Sama的个人记录_4_第1张图片

class Solution {
     
	/*
	* 【回溯法】
	* 思路:首先想到for语句嵌套,但其数量不确定,且时间复杂度爆炸
	* 	   对于这种次数不固定的嵌套,应该马上反应过来这是回溯问题
	* 
	*/
    public List<String> letterCombinations(String digits) {
     
    	  	
    	if(digits == null || digits.length() == 0)	return new ArrayList<String>();		// leetcode总会有空值test
    	traceBack(digits, "", 0);
    	return resList;
    	
    }
    
    String[] letterMap = {
     " ", " ", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};		// 按键对应“字母块”的字典
    List<String> resList = new ArrayList<String>();
    
    public void traceBack(String digits, String letter, int index) {
     
    	/*
    	* ★★★写出这个回溯方法是重点,难点,也是巧妙之处
    	* 
    	* 三个参数:
    	* ▷ digits是输入的字符串,每一层中需要通过index取出一个数字,来索引到那个"字母块"
    	* ▷ letter是关键!用于暂存已经遍历到的字母串
    	* ▷ index用于索引取出digits的某个数字,index随着层数变动
    	* 
    	* 回溯方法的停止条件(开始回溯)、如何给下一层traceback传参,更是该算法的灵魂
    	* ▷ 停止(并开始回溯)的条件是:index=length,index已经等于层数(输入字符串数字的个数)
    	* 	此时暂存串letter已经完全,把它add到最终结果resList中
    	* ▷ 传参:digits作为一个参考不需要改变,改变是索引它的那个index,也就是层数;
    	* 	letter暂存串加上此层次上读取的字母
    	*/
    	if(index == digits.length()) {
     
    		resList.add(letter);
    		return;
    	}
    	char c = digits.charAt(index);
    	int temp = Integer.valueOf(String.valueOf(c));
    	String letterPart = letterMap[temp];			// 上面这三行,是为了找到这一层的数字对应的“字母块”letterPart
    	for(int i = 0 ; i < letterPart.length() ; i++) {
     
    		traceBack(digits, letter + letterPart.charAt(i), index + 1);
    	}
    }

	// 总结:
	// ★☆★ 其实实现回溯的根源在于traceback方法的for语句
	// ★☆★ 暂存串暂存了这一条“试探”路径,也是实现此算法的关键
	// ★☆★ 回溯是很重要很重要很重要很重要的算法,背也要背会
}

 
 

 

▊【Q14】(ez) 最长公共前缀
 

编写一个函数来查找字符串数组中的最长公共前缀。

 
如果不存在公共前缀,返回空字符串 “”。

 
示例 1:

   输入: [“flower”,“flow”,“flight”]
   输出: “fl”
示例 2:

   输入: [“dog”,“racecar”,“car”]
   输出: “” 解释: 输入不存在公共前缀。
 
说明:

所有输入只包含小写字母 a-z 。

class Solution {
     
	/*
	* 暴力法就是选取一个字符串,置指针指向第一个,然后所有字符串首字母与其比较;若全部相同,指针+1后进行下一轮比较
	* 但这种方法不仅效率低下,还需要对越界问题进行处理,代码量不低
	* 以下的思路比较巧妙:
	*  		选取一个字符串作为操作基准,不断割短这个字符串,直到它是所有字符串的开头为止
	*/
    public String longestCommonPrefix(String[] strs) {
     
    	if(strs.length == 0)	return "";
    	String s = strs[0];
    	for(String each : strs) {
     
    		while(each.indexOf(s) != 0) {
     
    			s = s.substring(0, s.length()-1);		// "不断割短这个字符串,直到它是所有字符串的开头为止"
    		}
    	}    	
    	return s;
    }
    
    // 总结:
    // 遇到ez等级的题目,尽量抛弃脑中瞬间浮现的第一个暴力法 
}

 

 

▊【Q18】(md) 四数之和问题
 
   给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
 
注意

   答案中不可以包含重复的四元组。
 
示例

   给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。

   满足要求的四元组集合为: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ]

class Solution_18 {
     
    public List<List<Integer>> fourSum(int[] nums, int target) {
     
    	/*
    	* 【双指针算法】
    	* 之前详细分析了"三数之和问题",那是一个经典的三项双指针,此题是四项双指针 
    	* 
    	* 思路类似:
    	* 在"三数之和问题"中,for语句中为i,然后固定i、移动收缩双指针L,R
    	* 而在此题中,两个for语句嵌套(i,j一左一右),然后固定i,j、移动收缩双指针L,R
    	* 
    	* 细节同样有两处:
    	* 一是去重;二是在去重时防止越界
    	*/
    	
    	List<List<Integer>> resList = new ArrayList<>();
    	if(nums == null || nums.length < 4 )	return resList;
    	Arrays.sort(nums);
    	int len = nums.length;
   	
    	for(int i = 0 ; i < len - 3 ; i++) {
     
    		if(i > 0 && nums[i] == nums[i - 1])	continue;			// 去重
    		for(int j = len - 1 ; j > i ; j--) {
     
    			if(j < len-1 && nums[j] ==nums[j + 1] )	continue;		// 去重
    			
    			int L = i + 1;
    			int R = j - 1;
    			while(L < R && i < j) {
     
    				int sum = nums[i] + nums[L] + nums[R] + nums[j];
    				if(sum == target) {
     
    					resList.add(Arrays.asList(nums[i], nums[L], nums[R], nums[j]));
    					while(L < R && nums[L] == nums[L + 1])	L++;				// 去重(注意写上L
    					while(L < R && nums[R] == nums[R - 1])	R--;				// 去重
    					L++;
    					R--;
    				}else if(sum < target) {
     
    					L++;
    				}else if(sum > target) {
     
    					R--;
    				}
    			}
    		}
    	}
    	return resList;   	
    }
}

 

 

▊【Q20】(ez) 有效的括号(括号匹配问题)
 
   给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]'的字符串,判断字符串是否有效。
  
有效字符串需满足:
   左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 注意空字符串可被认为是有效字符串。
 
示例 1:
   输入: “([{}])”
   输出: true
示例 2:
   输入: “([)]”
   输出: false

class Solution_19 {
     
    public boolean isValid(String s) {
     
    	/*
    	* 思路:
    	* 1.使用HashMap进行匹配,使得代码和逻辑都更具美感
    	* 2.典型的栈结构问题。由于java 8,9有移除Stack的趋势,因此这里使用双端队列Deque,同样有PushPop特性
    	*/
    	if(s == null || s.length() == 0)	return true;	// leetcode传统艺能,null和0值不说就是true
    	Map<Character, Character> map = new HashMap<>();
    	map.put(')', '(');
    	map.put(']', '[');
    	map.put('}', '{');
    	Deque<Character> dq = new ArrayDeque<>(); 
    	for(char c : s.toCharArray()){
     
    		if(c == '(' || c == '[' || c == '{'){
     
    			dq.push(c);
    		}else{
     
    			if(dq.size() == 0 || map.get(c) != dq.pop())	return false;
    		}
    	}
    	return dq.size() == 0;
    }
}

 

 

 

 

 

 

 

 

 
Qs from https://leetcode-cn.com
♣ loli suuuki
♥ end

你可能感兴趣的:(Leetcode,算法,leetcode,数据结构)