leetcode 编程题
1.clone_graph
1 /** 2 * Definition for undirected graph. 3 * struct UndirectedGraphNode { 4 * int label; 5 * vector<UndirectedGraphNode *> neighbors; 6 * UndirectedGraphNode(int x) : label(x) {}; 7 * }; 8 */ 9 class Solution { 10 public: 11 UndirectedGraphNode *clone(UndirectedGraphNode *node, map<int,UndirectedGraphNode*> &table) 12 { 13 if(node==NULL) 14 return NULL; 15 16 if(table.find(node->label)!=table.end()) 17 return table[node->label]; 18 19 UndirectedGraphNode *newnode=new UndirectedGraphNode(node->label); 20 table[newnode->label]=newnode; 21 22 for(int i=0;i<node->neighbors.size();i++) 23 { 24 UndirectedGraphNode *neighbor=clone(node->neighbors[i],table); 25 newnode->neighbors.push_back(neighbor); 26 } 27 28 return newnode; 29 } 30 /** 31 * @param node: A undirected graph node 32 * @return: A undirected graph node 33 */ 34 UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) { 35 map<int,UndirectedGraphNode*> visitTable; 36 return clone(node,visitTable); 37 } 38 };
2.Palindrome Partitioning
理解 substr函数的用法
1 #include<string> 2 #include<iostream> 3 using namespace std; 4 main() 5 { 6 string s("12345asdf"); 7 string a=s.substr(0,5); //获得字符串s中 从第0位开始的长度为5的字符串//默认时的长度为从开始位置到尾 8 string b = s.substr(4); //获得字符串从第4位开始的字符串 9 cout<<a<<endl; 10 } 11 输出结果为: 12 12345 13 5asdf
Palindrome Partitioning 源码:
1 Given a string s, partition s such that every substring of the partition is a palindrome. 2 Return all possible palindrome partitioning of s. 3 For example, given s ="aab", 4 Return 5 6 [ 7 ["aa","b"], 8 ["a","a","b"] 9 ] 10 11 12 13 class Solution { 14 public: 15 //path保存每种方案,res所有方案 16 void dfs(string s,vector&path,vector>&res){ 17 18 //查到最后,将该方案添加,返回 19 if(s.size() < 1) 20 { 21 res.push_back(path); 22 return; 23 } 24 25 //从当前串的头开始,检查回文串 26 for(int i = 0;i<s.size(),i++) 27 { 28 int begin = 0; 29 int end = i; 30 while(begin < end){ 31 if(s[begin] == s[end]){ 32 begin++; 33 end--; 34 } 35 else 36 break; 37 } 38 if(begin >= end) 39 {//找到回文串 40 path.push_back(s.substr(0,i+1));//添加到path中 41 dfs(s.substr(i+1), path,res);//递归向后查 42 path.pop_back();//回溯,检查多种不同方案 43 } 44 } 45 46 47 } 48 49 //判断一个字符串是否为回文串 50 vector> partition(string s) { 51 vector>res; 52 vectorpath; 53 dfs(s,path,res); 54 return res; 55 } 56 };
3.valid-palindrome
在此介绍两个函数:
isalnum(char c) 用法:#include <ctype.h> 功能:判断字符变量c是否为字母或数字 说明:当c为数字0-9或字母a-z及A-Z时,返回非零值,否则返回零。 tolower(int c) 功 能: 把 字符转换成小写字母,非字母字符不做出处理 头文件:在VC6.0可以是 ctype.h或者 stdlib.h,常用ctype.h
valid-palindrome源码
bool isPalindrome(string s) { int i = 0; int len = s.size(); int j = len-1; while(i<j) { while(i<j&&!isalnum(s[i])) i++; while(i<j&&!isalnum(s[j])) j--; if(i<j && tolower(s[i])!=tolower(s[j])) { return false; } i++;j--; } return true; }
4.single-number
Given an array of integers, every element appears twice except for one. Find that single one. Note: Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory? //思路:两个相同的数异或为0 //例子:1^2^3^4^4^3^2 = 2^2^3^3^4^4^1 = 1 public class Solution { public int singleNumber(int[] A) { int result = A[0]; for(int i=1; i<A.length; i++){ result = result ^ A[i]; } return result; } }
5.single-number-ii
/* Given an array of integers, every element appears three times except for one. Find that single one. Note: Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory? */ int singleNumberII(int A[], int n) { int ans = 0; for (int i = 0; i < 32; i++) { int c = 0, d = 1<<i; for (int j = 0; j < n; j++) if (A[j] & d) c++; //对每一位进行判断,如果数组中的所有数字经过判断后发现结果不是3的倍数 说明出现次数不为3的那个数的 二进制为1.所以要或运算。这样ans为最后的结果 if (c%3) ans |= d; } return ans; }
6.two-sum
这里用到了C++中的哈希容器unordered_map vector<int> twoSum(vector<int>& nums, int target) { vector<int> res; int len = nums.size(); unordered_map<int, int> m; for (int i = 0; i < len; i++){ if (m.count(target - nums[i])){ res.push_back(m[target - nums[i]]+1); res.push_back(i+1); return res; } m[nums[i]] = i; } return res; } 补充知识: unordered_map::count 查找与指定键匹配的元素数。 size_type count(const Key& keyval) const; 参数 keyval 要搜索的键值。 备注 成员函数返回由分隔的范围中的元素数目
7. add-two-numbers
/* You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 0 -> 8 */ struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; /* 最直白的想法就是将两个字符串翻转, 然后相加,得到的结果再发转 现在的解法,直接从左到右相加,然后向右进位 */ class Solution { public: ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) { ListNode* ptr = new ListNode(0); ListNode* head = ptr; int tmp_carry = 0; int sum; while( l1 || l2 ) { sum = 0; if( l1 ) { sum += l1->val; l1 = l1->next; } if( l2 ) { sum += l2->val; l2 = l2->next; } ptr->next = new ListNode( (sum + tmp_carry)%10 ); ptr = ptr->next; tmp_carry = (sum + tmp_carry)/10; } if( tmp_carry ) { ptr->next = new ListNode( tmp_carry ); } return head->next; } }; 结果返回的是一个带头结点的链表,在链表的生成过程中,需要一个一个的产生节点来生成,每次生成链表中的一个节点。
8. longest-substring-without-repeating-characters
/* Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1 题意在原串中找到最长的每个字母最多出现一次的字符串 */ int lengthOfLongestSubstring(string s) { int i,j,len=0,maxx=0; bool sign[30]; memset(sign,0,sizeof(sign)); for(i=0,j=0;j<s.length();++j) { while(sign[s[j]-'a']==1) { sign[s[i]-'a']=0; ++i; } sign[s[j]-'a']=1; maxx=max(maxx,j-i+1); } return maxx; } //理解:在while循环中,虽然j没有改变,但是i的变化也会使得循环条件的变化
9. longest-palindromic-substring
/* Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. */ /* 解析: 使用动态规划的话,首先我们需要知道解法中得递推关系。比如字符串“ababa”,如果我们已经知道“bab”是回文,那么显然“ababa”也是回文,因为首字符和尾字符是相等的。 定义dp[i][j]:如果子串Si到Sj是一个回文串,那么该项为true,否则为false 我们知道有这样的递推关系如下: dp[i][j]为true 成立的条件是 dp[i+1][j-1] 为真并且Si==Sj 基础条件是: dp[i][i]=true 代表一个字符是一个回文串 dp[i][i+1]=true 代表相邻字符是回文串 那么在基础条件下 仅仅计算字符串长度分别为 3 4 一直到s.size() 是否是回文串即可,当然每次计算的时候 记录最长回文串的索引和回文串长度 */ string longestPalindrome(string s) { int i = 0; int j = 0; int len = s.size(); int k = 0; vector<vector<bool> > a(len,vector<bool>(len,false)); // bool a[1000][1000]={false}; int maxsize = 1; int maxindex = 0; for(i = 0;i<len;i++) { a[i][i]=true; } for(i=0;i<len-1;i++) { if(s[i]==s[i+1]) { a[i][i+1]=true; maxindex = i; maxsize = 2; } } for(k = 3;k<=len;k++) { for(i =0;i<len-k+1;i++) { j = i+k-1; if(s[i]==s[j]&&a[i+1][j-1]) { a[i][j]=true; maxindex = i; maxsize = k; } } } return s.substr(maxindex,maxsize); }
10. maximum-subarray
/* Find the contiguous subarray within an array (containing at least one number) which has the largest sum. For example, given the array[−2,1,−3,4,−1,2,1,−5,4], the contiguous subarray[4,−1,2,1]has the largest sum =6. click to show more practice. More practice: If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle. */ /* 解析: 典型的动态规划问题: 定义子问题:dp[i]为以第i个元素结尾的最大连续子数组和 然后在循环记录最大连续子数组和的同时记录 最大连续子数组和的值 等待循环完毕之时,即函数返回之时。 */ int maxSubArray(int A[], int n) { int i = 0; vector<int> sum(n,0); int maxr; sum[0]=A[0]; maxr = sum[0]; for(i = 1;i<n;i++) { sum[i]=max(A[i],sum[i-1]+A[i]); maxr = max(sum[i],maxr); } return maxr; }
11. unique-paths
/* A robot is located at the top-left corner of a m x n grid The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid How many possible unique paths are there? */ /* dp[i][j] 代表走到i行j列 的路径数 解析:从题目我们可以知道 dp[m][n]=dp[m-1][n]+dp[m][n-1] 基础条件:dp矩阵的第一行和第一列的值为1。意思就是说到达第一行和第一列的路径数为1. 这样就可以动态规划的求解除了第一行和第一列之外的 空格的路径数,不断的循环求解即可求得后下角空格的路径数 */ int uniquePaths(int m, int n) { vector<vector<int> > dp(m,vector<int>(n,0)); int i = 0; int j = 0; for(i=0;i<m;i++) { dp[i][0]=1; } for(i =0;i<n;i++) { dp[0][i]=1; } for(i = 1;i<m;i++) { for(j =1;j<n;j++) { dp[i][j]=dp[i-1][j]+dp[i][j-1]; } } return dp[m-1][n-1]; }
12. unique-paths-ii
/* Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How many unique paths would there be? An obstacle and empty space is marked as1and0respectively in the grid. For example, There is one obstacle in the middle of a 3x3 grid as illustrated below. [ [0,0,0], [0,1,0], [0,0,0] ] The total number of unique paths is2. Note: m and n will be at most 100. */ /* 解析: 动态规划 这个问题和前一个问题相比较,变化的就是加了障碍物,也就是说基础条件需要发生变化 第一行和第一列不在初始化为1 ,其值要看是否有障碍物 如果有障碍物 将其值赋值为0,如果没有障碍物 其值为前一个的dp值。对于第1行和第一列之后的值 如果有障碍物 赋值为0 ,没有障碍物,其值为左边dp值+上边dp值。 前提条件:dp[0][0]= obstacleGrid[0][0]==1?0:1 第一行和第一列是在第一个空格已知的前提下求解的 第一行和第一列之后的行数和列数是在 第一行和第一列的前提下求解的 */ int uniquePathsWithObstacles(vector<vector<int> > &obstacleGrid) { int i = 0; int j = 0; int m = obstacleGrid.size(); int n = obstacleGrid[0].size(); vector<vector<int> > dp(m,vector<int>(n,0)); dp[0][0]=obstacleGrid[0][0]==1?0:1; for(i = 1;i<m;i++) { dp[i][0]=obstacleGrid[i][0]==1?0:dp[i-1][0]; } for(i = 1;i<n;i++) { dp[0][i]=obstacleGrid[0][i]==1?0:dp[0][i-1]; } for(i = 1;i<m;i++) { for(j=1;j<n;j++) { if(obstacleGrid[i][j]==0) { dp[i][j] = dp[i-1][j]+dp[i][j-1]; } else { dp[i][j]=0; } } } return dp[m-1][n-1]; }
13. minimum-path-sum
/* Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path. Note: You can only move either down or right at any point in time. Subscribe to see which companies asked this question Hide Tags Array Dynamic Programming Show Similar Problems */ /* 解析: dp[0][0]=grid[0][0] 第一行的路径是左边的路径和当前位置的值相加的结果 第一列的路径是上边的路径和当前位置的值相机的结果 剩下点的路劲和都是来自二维数组上一行的最小路劲和或者来自左一列的最小路劲和与当前位置的值相加的结果 显然有:dp[m,n]=min(dp[m-1,n]+grid[m,n],dp[m,n-1]+grid[m,n]) */ int minPathSum(vector<vector<int> > &grid) { int i = 0; int j = 0; int m = grid.size(); int n = grid[0].size(); vector<vector<int> > dp(m,vector<int> (n,0)); dp[0][0]=grid[0][0]; for(i = 1;i<m;i++) { dp[i][0]=dp[i-1][0]+grid[i][0]; } for(i = 1;i<n;i++) { dp[0][i]=dp[0][i-1]+grid[0][i]; } for(i =1;i<m;i++) { for(j=1;j<n;j++) { dp[i][j]=min(dp[i-1][j]+grid[i][j],dp[i][j-1]+grid[i][j]); } } return dp[m-1][n-1]; }
14. climbing-stairs
/* ou are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? */ /* 解析: 动态规划 由题可知,dp[0]=1 dp[1]=2 爬到第三层楼的方法为使用climb1 step的方法+使用climb 2steps的方法 即dp[3]=dp[3-1]+dp[3-2] 综上:dp[i]=dp[i-1]+dp[i-2]; */ int climbStairs(int n) { vector<int> dp(n,0); dp[0]=1; dp[1]=2; int i = 0; for(i = 2;i<n;i++) { dp[i]=dp[i-1]+dp[i-2]; } return dp[n-1]; }
15. unique-binary-search-trees
/* Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For example, Given n = 3, there are a total of 5 unique BST's. */ /* 解析: 动态规划问题,所以必须努力去找到和以前的子问题的联系。 断言:由1,2,3,...,n构建的二叉查找树,以i为根节点,左子树由[1,i-1]构成,其右子树由[i+1,n]构成。 定义子问题:定义dp[i]为以1-i 能产生的二叉搜索树的数目 若数组为空,则只有一种BST,即空树,dp[0]=1; 若数组仅有一个元素1,单个节点,dp[1]=1; 若数组有两个元素1,2,则有两种可能,dp[2]=2; 若数组有三个元素1,2,3,则有5中情况,题目已经说了, n=4呢?显示此问题玄机的时候到了:寻找与上面已推出子问题的关系: 如果1为根,则左子树0个元素所以1种情况,右子树3个元素(2,3,4),显然为5种情况 如果2为根,则左子树1个元素所以1种情况,右子树2个元素(3,4),显然为2 如果3为根,则左子树2个元素所以2种情况,右子树1个元素(4),显然为2 如果4为根,则左子树3个元素所以5种情况,右子树3个元素(无)为一种情况,显然为5 也就是说 n=4 也就是说要考虑4种情况(可用循环,循环里面就是子问题了) 所以先把子问题就出来 然后在循环的求大问题 */ int numTrees(int n) { vector<int> dp(n+1,0); dp[0]=1; dp[1]=1; int i = 0; int j = 0; for(i=2;i<=n;i++) { for(j=1;j<=i;j++) { dp[i] += dp[j-1]*dp[i-j]; } } return dp[n]; }
16.best-time-to-buy-and-sell-stock
/* Say you have an array for which the i th element is the price of a given stock on day i. If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit. */ /* 解析: 初始条件就是dp[0]=prices[0] 然后在维护一个最大差值变量maxz dp[i]代表找这个数组里面的最小值 同时在求得最小值的时候记录maxz */ int maxProfit(vector<int> &prices) { int n = prices.size(); if(n==0) { return 0; } vector<int> dp(n,0); int i = 0; int maxz = 0; dp[0]=prices[0]; for(i=1;i<n;i++) { dp[i]=min(dp[i-1],prices[i]); maxz = max(maxz,prices[i]-dp[i]); } return maxz; }
17. 风口的猪-中国牛市
/* 风口之下,猪都能飞。当今中国股市牛市,真可谓“错过等七年”。 给你一个回顾历史的机会,已知一支股票连续n天的价格走势,以长度为n的整数数组表示,数组中第i个元素(prices[i])代表该股票第i天的股价。 假设你一开始没有股票,但有至多两次买入1股而后卖出1股的机会,并且买入前一定要先保证手上没有股票。若两次交易机会都放弃,收益为0。 设计算法,计算你能获得的最大收益。 输入数值范围:2<=n<=100,0<=prices[i]<=100 示例1 输入 3,8,5,1,7,8 输出 12 */ /* 解析: 思路和前一个题的思路相似,但是不同的是 从左往右是找dp[i]最小的,从右往左是找dp[i]最大的,为了避免跨界变量 (买入前一定要先保证手上没有股票),循环的找利益最大的。 */