给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
说明:
示例:
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
该题需要特别注意的是,给定的 m 是 nums1 除过 0 元素的其它元素个数,如:数组 [0] ,m 就为 0 ,而不是 1 ;
从两个数组的尾开始遍历,而不是头,这样容易将 nums2 的元素 存储在 nums1 数组中;
在循环时,需要判断 nums1 的元素个数的角标是否越界;
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m -1;
int l1 = m+n-1;
int l2 = n-1;
while(i >= 0 || l2 >= 0){
//判断 nums1 的有效元素是否已经越界,如果越界,直接将 nums2 数组剩余的元素直接存储在 nums1 中
if(i < 0){
nums1[l1--] = nums2[l2--];
//判断 nums2 数组是否越界,如果越界,说明 nums1 数组还未遍历结束,则直接将 nums1 中的数组“原封不动”地存储在原地
}else if(l2 < 0){
nums1[i--] = nums1[l1--];
}else if(nums2[l2] > nums1[i]){
//如果 nums2 的元素大于 nums1 的元素,直接将 nums2 元素存储在 nums1 数组的最后面
nums1[l1--] = nums2[l2--];
}else if(nums2[l2] < nums1[i]){
//如果 nums1 元素大于 nums2 元素,则先将 nums1 中元素向后挪一位,等待下次遍历将 nums2 元素存储在nums1 中
nums1[l1--] = nums1[i--];
}else{
//相当于上一步的存储
nums1[l1--] = nums2[l2--];
}
}
}
}
假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
示例:
给定 n = 5,并且 version = 4 是第一个错误的版本。
调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true
所以,4 是第一个错误的版本。
该题也属于二分查找,但是最重要的一点是,注意边界的情况,如果使用这种: mid = (right+left)/2 ,很可能会引起整数溢出的情况,因此,可以将上述的方法做一个变形: mid = (right-left)/2 + left ,先是做减法然后除以2,最后再加上 left ,这种方法在数学中和第一种其实结果一致;判断条件是 left < right ,只要不满足条件说明已经找到第一个错误的版本了;
public int firstBadVersion(int n) {
int left = 1, right = n;
while (left < right ) {
int mid = left + (right - left) / 2;
if (isBadVersion(mid)) {
right = mid;
} else {
left = mid + 1;
}
}
return l;
}
编写一个函数,以字符串作为输入,反转该字符串中的元音字母。
示例 1:
输入: "hello"
输出: "holle"
示例 2:
输入: "leetcode"
输出: "leotcede"
该题使用双指针是很容易求解的,因为题目要求是让我们将 s 中的元音字母进行翻转,所以明显使用 left 和 right 指针从前后两端开始遍历寻找;如果 left 找到元音字母后,就不用继续向后寻找(保持当前位置等待交换),而如果 right 也找寻到后,就和等待的 left 进行交换,循环推出条件是 left <= right ;String check = "aAoOeEiIuU"
表示所有的元音字母;
public String reverseVowels(String s) {
if(s == null || s.length() <= 1){
return s;
}
String check = "aAoOeEiIuU";
int l = 0;
int r = s.length()-1;
char[] res = new char[s.length()];
while(l <= r){
char c1 = s.charAt(l);
char c2 = s.charAt(r);
if(!check.contains((c1+""))){
res[l++] = c1;
}else if(!check.contains((c2+""))){
res[r--] = c2;
}else{
res[l++] = c2;
res[r--] = c1;
}
}
return new String(res);
}
给定一个字符串和一个字符串字典,找到字典里面最长的字符串,该字符串可以通过删除给定字符串的某些字符来得到。如果答案不止一个,返回长度最长且字典顺序最小的字符串。如果答案不存在,则返回空字符串。
示例 1:
输入:
s = "abpcplea", d = ["ale","apple","monkey","plea"]
输出:
"apple"
示例 2:
输入:
s = "abpcplea", d = ["a","b","c"]
输出:
"a"
该题只要去比较,列表 d 中的每个元素其中的每个字符在字符串 s 中存在的最多,即就可以看作是 s 字符串通过删除给定字符串的某些字符所得到的;
注意:如果答案不唯一时,返回的是“字典顺序最小的”那个字符串,如, a 和 c 都在 abpcplea 字符串中存在,但是 a 的 ACSII 值比 c 小,那么就返回字符串 a ,而不是 c ;
public String findLongestWord(String s, List<String> d) {
String longestWord = "";
for (String target : d) {
int l1 = longestWord.length(), l2 = target.length();
//判断特殊情况,如果 l1 大于 l2 ,说明之前的查到的字符串 longestWord 比 target 字符串更加合适,因此不需要再次比较
//如果 l1 等于 l2 ,说明出现了两个之前查到的字符串 longestWord 和 接下来的 target 字符串长度相等的情况,那么就要去判断它们在“字典”中的顺序了
if (l1 > l2 || (l1 == l2 && longestWord.compareTo(target) < 0)) {
continue;
}
//判断目标字符串,即列表 d 中的元素 target ,是否是 s 字符串的子字符串,如果是,则说明该目标字符串 target 目前是我们要找寻的字符串
if (isSubstr(s, target)) {
longestWord = target;
}
}
return longestWord;
}
//通过遍历比较,判断是否是子字符串
private boolean isSubstr(String s, String target) {
int i = 0, j = 0;
while (i < s.length() && j < target.length()) {
if (s.charAt(i) == target.charAt(j)) {
j++;
}
i++;
}
return j == target.length();
}
参考GitHub,CyC2018
给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。
注意: 您的方案应该在 O(log n)时间复杂度和 O(1)空间复杂度中运行。
示例 1:
输入: [1,1,2,3,3,4,4,8,8]
输出: 2
示例 2:
输入: [3,3,7,7,10,11,11]
输出: 10
该题使用双指针解题是一个很不错的方法,也很简单;但在解题时,需要注意:nums数组的长度和特殊情况:
只要将上述的特殊情况考虑清除,该题就会迎刃而解了。
当判断长度为1时直接返回第一个元素即可;否则,设置双指针从 nums 的起始位置开始遍历,不需要每次 +1 的遍历,由于该数组的每个元素都会出现两次,只有一个单一元素,可以直接一次 +2 的进行遍历,也保证时间复杂度的要求;只要 nums[i] == nums[j] 时,先让 i+=2 去判断是否越界,如果没有越界,则继续判断 j+=2 是否越界,如果越界说明最后一个数为单一元素,返回 nums[i] 即可;如果也没有越界,则 i 和 j 继续向后遍历,直到两者不相等为止。
class Solution {
public int singleNonDuplicate(int[] nums) {
if(nums.length == 1){
return nums[0];
}
int i = 0;
int j = 1;
while(j < nums.length){
if(nums[i] == nums[j]){
i += 2;
if(i == nums.length){
return 0;
}else if(j+2 == nums.length){
return nums[i];
}
j += 2;
}else{
return nums[i];
}
}
return 0;
}
}