以下题目来自Leetcode,中文网站:https://leetcode-cn.com/
1-两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
1.暴力法
思路很简单,就是耗时长了点,不多说了
vector<int> twoSum1(vector<int>& nums, int target) {
vector<int> ans;
for (auto i = 0; i < nums.size(); i++)
for (auto j = i + 1; j < nums.size(); j++)
if (nums[i] + nums[j] == target) {
ans.push_back(i);
ans.push_back(j);
}
return ans;
}
2.使用关联容器map
利用map高效查找的特性可以有效降低算法的时间复杂度
思路:
- 想要找到满足 a[i]+a[j]=target 的i,j
- 对每一个i, 以target-a[i]为key,i为value,构建map
- 遍历数组,对每一个a[i],在map中进行查找,若找到一个key为a[i],那么答案也就出现了
vector<int> twoSum2(vector<int>& nums, int target) {
map<int, int> numsMap;
vector<int> ans;
for (auto i = 0; i < nums.size(); i++)
numsMap[nums[i]] = i;
for (auto j = 0; j < nums.size(); j++)
{
int v = target - nums[j];
if (numsMap.count(v) && numsMap[v] != j)
{
ans.push_back(j);
ans.push_back(numsMap[v]);
return ans;
}
}
return ans;
}
注:利用map的下标查找会创建不存在的key的特性可以进一步改善代码,有时间我再写,5月6日更新,我写了,贴在下面。
vector<int> twoSum3(vector<int>& nums, int target) {
map<int, int> nums_map;
int i = 0;
while (i < nums.size()) {
if (nums_map.find(nums[i]) != nums_map.end())
return { i,nums_map.find(nums[i])->second };
nums_map[target-nums[i]] = i;
i++;
}
return {};
}
2-两数相加
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
思路:
- 链表对齐,构造一个进位数(没必要构造一个数组),相加、进位
- 如果一个链表到头了,不妨置尾为0,不影响结果
- 写得有点混乱,还得修改修改
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int sum = 0, c = 0;
vector<int> ans;
while (1) {
sum = (l1->val + l2->val + c) % 10;
c = (l1->val + l2->val + c) / 10;
ans.push_back(sum);
if (l1->next == NULL && l2->next == NULL) {
if (c == 1)ans.push_back(c);
break;
}
if (l1->next != NULL)
l1 = l1->next;
else
l1->val = 0;
if (l2->next != NULL)
l2 = l2->next;
else
l2->val = 0;
}
ListNode* head = new ListNode(0);
ListNode* temp = head;
for (auto i = 0; i < ans.size(); i++) {
ListNode* p = new ListNode(0);
p->val = ans[i];
temp->next = p;
temp = p;
}
return head->next;
}
3-无重复字符的最长字串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
1.暴力法
思路:
- 使用两个下标 i 和 j 表示待查找的最长字串的始末下标
- 以 i 遍历 , 同时从 i 开始以 j 向末尾遍历,同时以一个 k 从 i 向 j 遍历,并记录 i j 之间的距离
- 直到发现了一个s[k]==s[i],那么这一对(i,j)不是符合要求的,进入下一个i
int lengthOfLongestSubstring1(string s) {
int temp = 0;
int ans = 1;
if (s.size() != 0) {
for (int i = 0; i < s.size(); i++)
for (int j = i + 1; j < s.size(); j++) {
temp = j - i + 1;
for (int k = i; k < j; k++)
if (s[k] == s[j]) {
temp = 0;
break;
}
if (temp > ans) {
ans = temp;
}
if (temp == 0)break;
}
return ans;
}
else return 0;
}
2.改进方法
- 这个方法是在题目的评论区看见的,很快,也很简洁
- 同样是3个参数i,j,k,减少遍历的层数可以有效减少耗时
int lengthOfLongestSubstring2(string s) {
int i = 0, j, k, max = 0;
for (j = 0; j < s.size(); j++) {
for (k = i; k < j; k++)
if (s[k] == s[j]) {
i = k + 1;
break;
}
if (j - i + 1 > max)
max = j - i + 1;
}
return max;
}