1、两数之和
给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。
你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1]
C++版:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> res;
int n = nums.size();
int *a = new int[n];
for(int i = 0;i < n;i++) a[i] = nums[i];
sort(nums.begin(), nums.end());
int lhs = 0, rhs = n -1; //从两边开始查找
while(rhs > lhs){
if(nums[rhs] + nums[lhs] > target) rhs--;
else if(nums[rhs] + nums[lhs] < target) lhs++;
else{
int id1, id2;
for(int i = 0;i < n; i++){
if(a[i] == nums[lhs]){
id1 = i+1;
break;
}
}
for(int i = n - 1;i >= 0; i--){
if(a[i] == nums[rhs]){
id2 = i+1;
break;
}
}
res.push_back(min(id1, id2));
res.push_back(max(id1, id2));
return res;
}
}
}
};
这种方法首先把给定的Vector进行排序,然后从Vector的两端进行查找,其时间复杂度为O(nlogn),其空间复杂度为O(n)。这种方法相比于暴力求解的算法性能还是提升了一些。但是有没有更好的算法呢?
答案是肯定的,利用哈希表可以用空间换取时间,使得时间复杂度降到O(n)。创建哈希表时要注意,不需要一开始就建立哈希表并扫描全部数据,可以边创建边建立哈希表。代码如下:
class Solution {
public:
vector<int> twoSum(vector<int> &numbers, int target) {
map<int, int> hashmap;
vector<int> res;
for(int i = 0;i < numbers.size();i++){
if(hashmap.find(target-numbers[i]) != hashmap.end()){
res.push_back(hashmap[target-numbers[i]]+1);
res.push_back(i+1);
return res;
}
hashmap[numbers[i]] = i;
}
return res;
}
};
Python版:
2. 两个排序数组的中位数
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 。
请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。
你可以假设 nums1 和 nums2 不同时为空。
示例 1:
nums1 = [1, 3] nums2 = [2]
中位数是 2.0 示例 2:nums1 = [1, 2] nums2 = [3, 4]
中位数是 (2 + 3)/2 = 2.5
由于两个vector是有序的,我们可以是用来类似归并排序的方法将两个vector进行结合,注意由于只需要得到中位数,故没有必要添加所有数据,到达中位数即可。
class Solution {
public:
double findMedianSortedArrays(int A[], int m, int B[], int n) {
vector<int> C;
int i, j;
int mid = (m+n) / 2 + 1;
for(i=0, j=0;i<m && j<n;){
if(A[i] > B[j]){
C.push_back(B[j++]);
}
else{
C.push_back(A[i++]);
}
if(C.size() == mid){
break;
}
}
while(C.size() != mid){
if(i < m)
C.push_back(A[i++]);
if(j < n)
C.push_back(B[j++]);
}
if ((m+n) % 2 == 0)
return (C[C.size()-1] + C[C.size()-2]) / 2.0;
return *(C.end()-1);
}
};
3.无重复字符的最长子串
给定一个字符串,找出不含有重复字符的最长子串的长度。
示例 1:
输入: “abcabcbb” 输出: 3 解释: 无重复字符的最长子串是 “abc”,其长度为 3。 示例 2:输入: “bbbbb” 输出: 1 解释: 无重复字符的最长子串是 “b”,其长度为 1。 示例 3:
输入: “pwwkew” 输出: 3 解释: 无重复字符的最长子串是 “wke”,其长度为 3。
请注意,答案必须是一个子串,”pwke” 是一个子序列 而不是子串。
这道题也是建立一个map,然后使用left去储存当重复字符出现时最左侧的索引,并去掉重复元素的重复个数。很简单有效的思路,map的key值是可以重复出现的。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int left = 0, maxlen = 0;
unordered_map<char, int> charmap;
if(s.length() == 0) return 0;
for(int i=0; i < s.length();i++){
if(charmap.find(s[i]) != charmap.end()){
left = max(left, charmap[s[i]] + 1);
}
maxlen = max(maxlen, i-left+1);
charmap[s[i]] = i;
}
return maxlen;
}
};
4.两数相加
给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8 原因:342 + 465 = 807
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
//进位
int carry = 0;
ListNode* head = new ListNode(0);
ListNode* pre = head;
while(l1 != NULL || l2 != NULL || carry!=0){ //为null相当于零,但不能同时为null
int sum = (l1 == NULL ? 0:l1->val) + (l2 == NULL ? 0:l2->val) + carry;
ListNode* cur = new ListNode(sum%10); //当前节点的值为个位数
carry = sum / 10;
pre->next = cur;
pre = cur; // 把pre从head指向cur
l1 = (l1==NULL ? l1 : l1->next); //寻找下一个节点
l2 = (l2==NULL ? l2 : l2->next);
}
return head->next;
}
};
声明
以上代码均参考于牛客网并在牛客网测试成功。参考了各位大佬的思路整理而成,希望大家一起学习~