leetcode刷题记录(905、804、657、922)

2019.1.5 leetcode 刷题总结

题号:905

给定一个非负整数数组 A,返回一个由 A 的所有偶数元素组成的数组,后面跟 A 的所有奇数元素。
你可以返回满足此条件的任何数组作为答案。

示例:
输入:[3,1,2,4]
输出:[2,4,3,1]
输出 [4,2,3,1],[2,4,1,3] 和 [4,2,1,3] 也会被接受。

我的想法:

双指针法:一个指向奇数的指针,一个指向偶数的指针,遍历数组,不断移动偶数指针,直到它指向偶数,将偶数和奇数数值调换,奇数指针向前移动,不断重复,直到偶数指针指向最后一个元素

对应程序:

// java
class Solution {
    public int[] sortArrayByParity(int[] A) {
        // 指向奇数的指针
    	int j = 0;
        // 指向偶数的指针
    	int k = 0;
    	while(k < A.length) {
            // 当偶数指针指向偶数
    		if(A[k] % 2 == 0) {
                // 交换两个指针指向的数值
    			int temp = A[k];
    			A[k] = A[j];
    			A[j] = temp;
    			// 指向奇数的指针向前移动
    			j++;
    		}
    		// 不断移动指向偶数的指针
    		k++;
    	}
    	
        return A;
    }
}

题号:804

国际摩尔斯密码定义一种标准编码方式,将每个字母对应于一个由一系列点和短线组成的字符串, 比如: “a” 对应 “.-”, “b” 对应 “-…”, “c” 对应 “-.-.”, 等等。
为了方便,所有26个英文字母对应摩尔斯密码表如下:
[".-","-…","-.-.","-…",".","…-.","–.","…","…",".—","-.-",".-…","–","-.","—",".–.","–.-",".-.","…","-","…-","…-",".–","-…-","-.–","–…"]
给定一个单词列表,每个单词可以写成每个字母对应摩尔斯密码的组合。例如,“cab” 可以写成 “-.-…–…”,(即 “-.-.” + “-…” + ".-"字符串的结合)。我们将这样一个连接过程称作单词翻译。
返回我们可以获得所有词不同单词翻译的数量。

例如:
输入: words = [“gin”, “zen”, “gig”, “msg”]
输出: 2
解释:
各单词翻译如下:
“gin” -> “–…-.”
“zen” -> “–…-.”
“gig” -> “–…--.”
“msg” -> “–…--.”
共有 2 种不同翻译, “–…-.” 和 “–…--.”.

我的想法:

  1. 定义字典:小写字母和摩尔斯密码的关系映射
  2. 遍历数组,针对每个单词,将其转换为摩尔斯密码所表示的字符串,存入Set中
  3. 返回Set集合的大小

对用程序:

// java
class Solution {
    // 用数组下标和字符串作映射,不需要map
    private static final String[] DICTIONARY = {
			".-","-...","-.-.","-..",".","..-.","--.","....","..",
			".---","-.-",".-..","--","-.","---",".--.","--.-",
			".-.","...","-","..-","...-",".--","-..-","-.--","--.."};
    
    public int uniqueMorseRepresentations(String[] words) {
    	Set<String> res = new HashSet<>();
    	
    	for(String word : words) {
    		StringBuilder sb = new StringBuilder();
    		for(char c : word.toCharArray()) {
                // 利用小写字母的ASCII码值
                // 减掉97,变成数组下标
    			sb.append(DICTIONARY[c - 97]);
    		}
    		
    		res.add(sb.toString());
    	}
    	
        return res.size();
    }
}

题号:657

在二维平面上,有一个机器人从原点 (0, 0) 开始。给出它的移动顺序,判断这个机器人在完成移动后是否在 (0, 0) 处结束。
移动顺序由字符串表示。字符 move[i] 表示其第 i 次移动。机器人的有效动作有 R(右),L(左),U(上)和 D(下)。如果机器人在完成所有动作后返回原点,则返回 true。否则,返回 false。
注意:机器人“面朝”的方向无关紧要。 “R” 将始终使机器人向右移动一次,“L” 将始终向左移动等。此外,假设每次移动机器人的移动幅度相同。

示例 1:
输入: “UD”
输出: true
解释:机器人向上移动一次,然后向下移动一次。所有动作都具有相同的幅度,因此它最终回到它开始的原点。因此,我们返回 true。
示例 2:
输入: “LL”
输出: false
解释:机器人向左移动两次。它最终位于原点的左侧,距原点有两次 “移动” 的距离。我们返回 false,因为它在移动结束时没有返回原点。

我的想法:

  1. 把向上移动(U)和向下移动(D)看做一组,把向左移动(L)和向右移动(R)看作一组
  2. 用两个栈分别记录两组行动,当栈为空时或栈中有此行动时,当前行动入栈;否则移除栈顶元素
  3. 最后看两个栈的元素是否都为零,若是,返回true;否则返回false

对应程序:

// java
class Solution {
    public boolean judgeCircle(String moves) {
		if(moves.length() % 2 != 0) {
			return false;
		}
		
		LinkedList<Character> udStack = new LinkedList<>();
		LinkedList<Character> lrStack = new LinkedList<>();
		
		for(char move : moves.toCharArray()) {
			switch(move) {
			case 'U':
			case 'D':
				howToDo(udStack, move);
				break;
			case 'L':
			case 'R':
				howToDo(lrStack, move);
				break;
			}
		}
		
		if(udStack.size() != 0 || lrStack.size() != 0) {
			return false;
		}
		
        return true;
    }
    
    private void howToDo(LinkedList<Character> stack, char c) {
		if(stack.size() == 0 || stack.contains(c)) {
			stack.addFirst(c);
		}else {
			stack.removeFirst();
		}
	}
}

优化:

以上方法显然有些麻烦,其实,分别记录四种方向的移动次数,比较对应行动方向(U-D,L-R)的移动次数是否相同即可

程序:
// java
class Solution {
    public boolean judgeCircle(String moves) {
    	// 参数检查,步数为奇数一定不能回到原点
		if(moves.length() % 2 != 0) {
			return false;
		}
		
		int u = 0,
			d = 0,
			l = 0,
			r = 0;
		
		for(char move : moves.toCharArray()) {
			switch(move) {
			case 'U':
				u++;
				break;
			case 'D':
				d++;
				break;
			case 'L':
				l++;
				break;
			case 'R':
				r++;
				break;
			}
		}
		
		return u == d && l == r;
	}
}

题号:922

给定一个非负整数数组 A, A 中一半整数是奇数,一半整数是偶数。
对数组进行排序,以便当 A[i] 为奇数时,i 也是奇数;当 A[i] 为偶数时, i 也是偶数。
你可以返回任何满足上述条件的数组作为答案。

示例:
输入:[4,2,5,7]
输出:[4,5,2,7]
解释:[4,7,2,5],[2,5,4,7],[2,7,4,5] 也会被接受。

我的想法:

双指针法:一个指向数组中的数字,另一个指向该数字的前一个数字。判断当前数字是否符合规则,若符合,指针向前移动;若不符合,移动第二个指针,移动的大小为2,同样找到不符合规则的数字,交换,重复

对应程序:

// java
class Solution {
    public int[] sortArrayByParityII(int[] A) {
    	// 遍历整个数组的指针
    	int j = 0;
    	// 和指针j错开一位的指针
    	int k = 1;
    	
    	while(j < A.length) {
    		// 若当前位置上的数字不符合规则
    		// (奇数 + 偶数 = 偶数 + 奇数 = 奇数)
    		if((A[j] + j) % 2 != 0) {
    			// 找到对应不符合规则的数
    			// (若当前是奇数下标值为偶数,那么就去找偶数下标值为奇数的数)
    			if((A[k] + k) % 2 != 0) {
    				// 交换两个数
    				int temp = A[k];
    				A[k] = A[j];
    				A[j] = temp;
    				// 指针后移
    				j++;
    				k = j + 1;
    			}else {
    				// 去下一个位置找
    				k += 2;
    			}
    		}else {
    			// 指针后移
    			j++;
    			k = j + 1;
    		}
    	}
    	
        return A;
    }
}

优化:

其实没有必要检查每一个数字和下标是否符合规则,只检查奇数下标或偶数下标的数即可,因为数组中奇偶数字各一半,若偶数位置出现了不符合规则的数字,那么奇数位置上一定也存在不符合规则的数字

程序:
// java
class Solution {
    public int[] sortArrayByParityII(int[] A) {
    	// 指向奇数下标的指针
        int j = 1;
        // 只遍历偶数下标的数字
        for(int i = 0; i < A.length - 1; i += 2) {
        	// 若不符合条件
            if(A[i] % 2 != 0) {
            	// 去奇数下标的数字中寻找不符合规则的数字
                while(A[j] % 2 != 0) { 
                    j += 2;
                }
                // 交换数字
                int temp = A[j];
                A[j] = A[i];
                A[i] = temp;
            }
        }
        
        return A;
    }
}

以上两种方法都是在原数组的基础上对数组进行修改并返回的,也就是没有使用额外的存储空间,当然这道题也可以定义一个新的数组,遍历原数组,将奇数填充到新数组的奇数索引中,把偶数填充到偶数索引中,再将新数组返回即可,这里就不提供代码了,大家可以自己写一写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值