【算法设计作业】week3
来源:互联网 发布:linux vi 批量删除 编辑:程序博客网 时间:2024/06/07 04:52
照例选题写思路
1.3Sum
来源:https://leetcode.com/problems/3sum/description/
题意
给出一串数,叫你找出所有的a,b,c使得a+b+c=0;要注意的是给出的数,可能重复。
思路
将输入的数排序,从头到尾对每一不同数字循环,下标为i,target = -i。并从用指针指向front = i+1,back = j + 1;
·如arr[front] + arr[back] > target, 说明太大,back–,移动到上一更小的数(因为有序,所以移动到的必然是更小的);
·如arr[front] + arr[back] < target, 说明太小,front++,移动到下一更大的数(因为有序,所以移动到的必然是更大的)。
·如arr[front] + arr[back] == target, 说明符合要求,将这个三元组加到结果集中。
重复上述判定,直到i循环结束。
这样复杂度仅为O(n^2),避免了三重循环的O(n^3)复杂度。
代码
vector<vector<int> > threeSum(vector<int> &num) { vector<vector<int> > res; std::sort(num.begin(), num.end()); for (int i = 0; i < num.size(); i++) { int target = -num[i]; // positive + positive > 0, it's impossible to get a negitive by positive+positive if (target < 0) break; int front = i + 1; int back = num.size() - 1; while (front < back) { int sum = num[front] + num[back]; // Finding answer which start from number num[i] if (sum < target) front++; else if (sum > target) back--; else { vector<int> triplet(3, 0); triplet[0] = num[i]; triplet[1] = num[front]; triplet[2] = num[back]; res.push_back(triplet); // Processing duplicates of Number 2 // Rolling the front pointer to the next different number forwards while (front < back && num[front] == triplet[1]) front++; // Processing duplicates of Number 3 // Rolling the back pointer to the next different number backwards while (front < back && num[back] == triplet[2]) rear--; } } // Processing duplicates of Number 1 while (i + 1 < num.size() && num[i + 1] == num[i]) i++; } return res;}
2.3Sum Closest
题意
与上一题类似,不过另外给出了一个target,要求找出a+b+c = sum中最接近 target的sum。
思路
思路和上一题是一样的,不过要给多个变量记录最接近target的结果而已。
代码
class Solution {public: int threeSumClosest(vector<int>& nums, int target) { if(nums.size() < 3) return 0; int closest = nums[0] + nums[1] + nums[2]; std::sort(nums.begin(), nums.end()); for(int first = 0; first < nums.size()-2; first++) { int second = first + 1; int third = nums.size()-1; while(second < third) { int curSum = nums[first] + nums[second] + nums[third]; if (curSum == target) return curSum; if(abs(target-curSum)<abs(target-closest)) { closest = curSum; } if(curSum > target) { --third; } else { ++second; } } } return closest; }};
3.4Sum
题意
与上一题类似,不过要求计算4个数的和,a+b+c+d的和。
思路
类似的,双重循环套一个线性寻找。
注意两个点:1.重复数字的处理 2.对于两个循环,有些情况开头就不符合条件的,比如最小sum > targer, 最大sum < target这些情况,不用再继续,直接break或者continue。
代码
class Solution {public: vector<vector<int>> fourSum(vector<int>& nums, int target) { int n = nums.size(); vector<vector<int>> res; if(nums.size() < 4) return vector<vector<int>>(); std::sort(nums.begin(), nums.end()); for(int i = 0; i < n - 3;i++) { if(i > 0 && nums[i] == nums[i-1]) continue; // decrease duplicate if(nums[i] + nums[i+1]+ nums[i+2] +nums[i+3] > target) break; // too large, search finished if(nums[i] + nums[n-3] + nums[n-2] + nums[n-1] < target) continue; // too small for(int j = i + 1; j < n - 2; j++ ) { if(j > i+1 && nums[j] == nums[j-1]) continue; // decrease duplicate if(nums[i]+nums[j]+nums[j+1]+nums[j+2] > target) break; // too large if(nums[i] + nums[j] + nums[n-2] + nums[n-1] < target) continue; // too small int front = j + 1, back = n-1; while(front < back) { int sum = nums[front] + nums[back] + nums[i] + nums[j]; if (sum < target) { front++; } else if(sum > target) { back--; } else { vector<int> tmp = {nums[i], nums[j], nums[front], nums[back]}; cout << nums[i] << ' ' << nums[j] << ' ' << nums[front] << ' ' << nums[back] << endl; res.push_back(tmp); do{front++;}while(front < back && nums[front] == nums[front-1]); do{back--;}while(front < back && nums[back] == nums[back+1]); } } } } return res; }};
4. Remove Nth Node From End of List
题意
给出一个链表,要求删除倒数第n个结点
思路
1.最直接的第一个思路就是,遍历一遍,数一下一共多少个结点,就知道倒数第n个是顺数第几个,然后就可以将之删除。这个复杂度是O(2n).
2.更好的一个思路,是复杂度为O(n)。我想不出,参考的http://www.cnblogs.com/grandyang/p/4606920.html
“这道题让我们移除链表倒数第N个节点,限定n一定是有效的,即n不会大于链表中的元素总数。还有题目要求我们一次遍历解决问题,那么就得想些比较巧妙的方法了。比如我们首先要考虑的时,如何找到倒数第N个节点,由于只允许一次遍历,所以我们不能用一次完整的遍历来统计链表中元素的个数,而是遍历到对应位置就应该移除了。那么我们需要用两个指针来帮助我们解题,pre和cur指针。首先cur指针先向前走N步,如果此时cur指向空,说明N为链表的长度,则需要移除的为首元素,那么此时我们返回head->next即可,如果cur存在,我们再继续往下走,此时pre指针也跟着走,直到cur为最后一个元素时停止,此时pre指向要移除元素的前一个元素,我们再修改指针跳过需要移除的元素即可。”
代码
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */class Solution {public: ListNode* removeNthFromEnd(ListNode* head, int n) { ListNode* first = head, *cur = head; for(int i = 0; i < n; i++) first = first -> next; if(first == NULL) { return head -> next; }else { while(first -> next != NULL) { first = first -> next; cur = cur -> next; } cur -> next = cur ->next ->next; return head; } }};
5. Valid Parentheses
题意
其实就是括号匹配,给一个字符串,包含()[]{}这三种括号,判断这个括号匹不匹配。
思路
很简单,借助一个栈,左括号入栈。如果是右括号,若栈为空直接返回false。若栈不为空,和栈顶比较,若匹配则出栈,否则返回false。等字符串遍历完毕,若栈为空,则说明括号全部匹配,返回true。
代码
class Solution {public: bool isValid(string s) { stack<char> stk; for(int i = 0; i < s.size(); i++) { if (s[i] == ')' || s[i] == '}' || s[i] == ']') { if(stk.empty()) return false; else { if ((stk.top() == '[' && s[i] == ']') || (stk.top() == '{' && s[i] == '}') || (stk.top() == '(' && s[i] == ')')) stk.pop(); else return false; } } else if (s[i] == '(' || s[i] == '{' || s[i] == '[') { stk.push(s[i]); } else { continue; } } return stk.empty(); }};
6.Merge Two Sorted Lists
题意
合并两个有序链表,不难。
思路
比较两条链表的最前面元素,哪个比较小,就放到新链表中。如果其中一个已经为空,直接将另一个放进就好。
代码
public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { ListNode* head = new ListNode(-1), *tmp; ListNode* rear = head; while (l1 != NULL || l2 != NULL) { if(NULL == l1 && NULL != l2) { tmp = l2; l2 = l2->next; } else if(NULL == l2 && l1 != NULL) { tmp = l1; l1 = l1 -> next; } else { if(l1->val < l2->val) { tmp = l1; l1 = l1-> next; } else { tmp = l2; l2 = l2->next; } } rear -> next = new ListNode(tmp->val); rear = rear->next; } return head -> next; }};
我叫了,才突然想到,其实可以减少很多内存开销而不用new的。用的discussion中的代码,如下
class Solution {public: ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { ListNode dummy(INT_MIN); ListNode *tail = &dummy; while (l1 && l2) { if (l1->val < l2->val) { tail->next = l1; l1 = l1->next; } else { tail->next = l2; l2 = l2->next; } tail = tail->next; } tail->next = l1 ? l1 : l2; return dummy.next; }};
另一个递归的方法
class Solution {public: ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { if(l1 == NULL) return l2; if(l2 == NULL) return l1; if(l1->val < l2->val) { l1->next = mergeTwoLists(l1->next, l2); return l1; } else { l2->next = mergeTwoLists(l2->next, l1); return l2; } }};
7.Generate Parentheses
题意
·给出一个数字n,生成所有合法的的n对括号对的组合。
例如,
For example, given n = 3, a solution set is:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
思路
1
我们发现,n=2的结果,可以基于n=1的结果推出……n=k的结果可以基于 k-1的结果推出。于是我们就可以这样做。原理就是在上一轮的“(”后插入“()”。然后去重。
class Solution {// 注意:这一段代码思路是正确的,只是不知道哪里问题,最后会多出一个“”空字符串,而且次序和标答不同,因而过不了。public: vector<string> generateParenthesis(int n) { vector<string> ans({"()"}), tmp; if (n == 0) return tmp; else { for(int i = 1; i < n; i++) { tmp.clear(); for(int ii = 0; ii < ans.size(); ii++) { tmp.push_back(insertToString(ans[ii], 0)); int len = ans[ii].size(); for(int j = 0; j < len; j++) { if(ans[ii][j] == '(') { tmp.push_back(insertToString(ans[ii], j+1)); } } } std::unique(tmp.begin(), tmp.end()); ans.swap(tmp); } return ans.reverse(); } } string insertToString(string& s, int pos) { // string tmp(s, 0, pos); tmp += "()"; for(int i = pos; i < s.size(); i++) { tmp += s[i]; } cout << tmp << endl; return tmp; }};
输出的结果是正确的,但是次序有问题,因而过不了。
2
思路二,可以过而且很简洁。参考
http://blog.csdn.net/yutianzuijin/article/details/13161721
- 【算法设计作业】week3
- Week3 作业
- WEEK3作业
- week3作业
- c++ 程序设计 week3 作业
- 算法设计Week3 LeetCode Algorithms Problem #133 Clone Graph
- Logistic Regression WEEK3编程作业
- 作业Week3 "Stopwatch: The Game"
- Stanford 算法课 week3
- 算法设计作业;贪心;
- 算法设计作业1
- 算法设计作业2
- 算法设计作业3
- 算法设计作业4
- 算法设计作业5
- 算法设计作业6
- 算法设计作业7
- 算法设计作业8
- 647. Palindromic Substrings
- Java--变量
- HashMap的工作原理【面试】
- FTPrep, 73 Set Matrix Zeroes
- thinking in java——复用类
- 【算法设计作业】week3
- GIT学习笔记
- LeetCode 136. Single Number (Easy)
- 图文教你理解单片机STM32时钟
- static+final与final区别,静态常量与常量
- 工厂模式
- JMeter测试网站性能吞吐量
- 欢迎使用CSDN-markdown编辑器
- ubuntu安装eclipse