two sum
在有序数组中找到两个数,使之和为目标
code1
哈希表记录值对应的下标,每次从已记录的hash中寻找是否存在构成和的另一个值。因为下标在访问后才记录进hash,因此不会出现重复下标的情况。时间复杂度O(n)
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ans;
map<int, int> hash;
for(int i=0; i<nums.size(); i++) {
int other = target - nums[i];
if(hash.find(other)!=hash.end()){
ans.push_back(i);
ans.push_back(hash[other]);
break;
}
hash[nums[i]] = i;
}
return ans;
}
};
code2
循环遍历
for(int i=0; i<nums.length-1; i++){
for(int j=i+1; j<nums.length; j++){
if(nums[i] + nums[j] == target){
return new int[]{i, j};
}
}
}
两数平方和
给一个数,判断这个数能否是两个数的平方和
code1
首先查找范围应该是$0到\sqrt x$
int a = (int) Math.sqrt(c);
int limit = a/2;
while (a >= limit){
double b = Math.sqrt(c - a * a);
if (b - (int)b == 0) return true;
else a--;
}
return false;
code2
改进,双指针
int i = 0;
int j = (int) Math.sqrt(c);
while (i <= j){ //eg:1*1 + 1*1 = 2
int res = i*i + j*j;
if (res == c) return true;
else if(res > c) --j;
else ++i;
}
return false;
反转字符串中的元音字符
code1
从首部和尾部向内搜索成对出现的元音交换
public static String reverseVowels(String s){
int length = s.length();
int i = 0;
int j = length-1;
char[] chars = s.toCharArray();
Set<Character> vowels = new TreeSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));
while (i <= j){
while(i<length&&!vowels.contains(chars[i])) ++i;
while(j>-1&&!vowels.contains(chars[j])) --j;
if (i > j) break;
char t = chars[i];
chars[i] = chars[j];
chars[j] = t;
i++;j--;
}
return String.copyValueOf(chars);
}
code2
遇元音的指针等待,反过来,不遇元音就前进
public static String reverseVowels(String s){
int i = 0;
int j = s.length()-1;
char[] chars = s.toCharArray();
Set<Character> vowels = new TreeSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));
while(i<=j){
char ci = chars[i];
char cj = chars[j];
if (!vowels.contains(ci)) {
i++;
}else if (!vowels.contains(cj)){
j--;
}else{
chars[i++] = cj;
chars[j--] = ci;
}
}
return String.copyValueOf(chars);
}
回文字符串
code
问题点就是遇到删除左或者删除右都可行,但是只有一种是回文的情况。
class Solution {
public boolean isPalindrome(String s){
for (int i=0; i<s.length()/2; i++){
if (s.charAt(i) != s.charAt(s.length()-1-i)){
return false;
}
}
return true;
}
public boolean validPalindrome(String s) {
int i=0;
int j=s.length()-1;
while (i<j && s.charAt(i) == s.charAt(j)){i++; j--;};
if (i>=j) return true;
return isPalindrome(s.substring(i, j)) || isPalindrome(s.substring(i+1, j+1));
}
}
归并两个有序数组
code
正面写,顺着比较大小挨个放
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i = 0; int j = 0; int k = 0;
int[] nums3 = new int[m+n];
while (i < m && j < n){
if (nums1[i] < nums2[j]){
nums3[k++] = nums1[i++];
}else{
nums3[k++] = nums2[j++];
}
}
if (i == m){
while(j < n) nums3[k++] = nums2[j++];
}else{
while(i < m) nums3[k++] = nums1[i++];
}
for (k = 0; k<m+n; k++){
nums1[k] = nums3[k];
}
}
}
code
倒过来写,从数组的尾部开始填。因为正着写不新建数组的话有一个缺点就是插入元素会产生覆盖
int i = m - 1;
int j = n - 1;
int k = m+n - 1;
while (i>-1 && j>-1)
nums1[k--] = (nums1[i] < nums2[j]) ? nums2[j--] : nums1[i--];
while (j>-1)
nums1[k--] = nums2[j--];
判断链表是否存在环
code
跑的人比走的人快,超圈
关于空指针的问题,首先head不能为空,然后正在的俩人不能为空(同时验证走的下一步不是空的),跨两步的人中间跨的一步不能为空
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode v = head;
ListNode v2 = head;
if(head == null)
return false;
while(v != null && v2 != null && v2.next != null){
v = v.next;
v2 = v2.next.next;
if (v == v2) return true;
}
return false;
}
}
最长子序列
其中的关键是判断子串的算法
/**
* 最长子序列
* https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/description/
* 在父串中左右扫描,直到子串中每一个字符都在父串中被找到
*/
public String findLongestWord(String s, List<String> d) {
String res = ""; int length=0;
for (String per : d) {
int i = 0, j = s.length() - 1;
int m = 0, l = per.length() - 1;
while (i <= j && m<l+1 && m<per.length()) { //由于需要使m、l交错,所以要保证索引
char c1 = s.charAt(i++), c2 = s.charAt(j--), c3 = per.charAt(m), c4 = per.charAt(l);
if (c1 == c3 && m != l+1) { //为了防止m==l时,m或l指向的值没有被检测
m++;
}
if (c2 == c4 && m != l+1) {
l--;
}
}
if (m == l+1 && (per.length() > length || (per.length() == length && per.compareTo(res) < 0))) {
res = per;
length = per.length();
}
}
return res;
}
大佬的写法
class Solution {
public String findLongestWord(String s, List<String> d) {
String longest = "";
for (String dictWord : d) {
int i = 0;
for (char c : s.toCharArray())
if (i < dictWord.length() && c == dictWord.charAt(i)) i++;
if (i == dictWord.length() && dictWord.length() >= longest.length())
if (dictWord.length() > longest.length() || dictWord.compareTo(longest) < 0)
longest = dictWord;
}
return longest;
}
}
结论上都是一样的,判断子串,判断长度,判断字典序;