leetcode题解日练--2016.7.23
2016-07-24 01:58
148 查看
日练三题,冰冻三尺非一日之寒。
2、链表插入排序;
3、链表排序 。
——梭罗《瓦尔登湖》
If there are multiple solutions, return any subset is fine.
Example 1:
nums: [1,2,3]
Result: [1,2] (of course, [1,3] will also be ok)
Example 2:
nums: [1,2,4,8]
Result: [1,2,4,8]
tag:数学、DP
题意:从一个集合中去寻找满足集合内部每两个元素都存在非1公约数的子集。
思路:
1、本来想从前往后去找,后来发现不太对劲,又从后往前去找,好像又没找到什么规律。后面一怒之下打了两小时乒乓球加桌球,好像开窍了。
还是看一个栗子加深理解吧,也不举太复杂的栗子,就[0,1,2,3,4,5,6,7,8,9,10]其实本来不应该有0,但是为了表示的方便,暂时加进来,不考虑就是了。
从大到小遍历这个数组,dp[i]中代表以元素i作为结尾的最大集合长度。dp[10] = 1,然后逆推往回求dp[9],从9一直到最后找能被10整除的数字,没这样的不存在,所以dp[9]=1,同理dp[8]=dp[7]=dp[6]=1.到dp[5]的时候,向后找找到了10能整除5,所以dp[5] = 2,同理dp[4]找到8、dp[3]找到6或者9,因为dp[6]=dp[9]=1,所以dp[3]找到他俩中的较大值再加1dp[3]=2,也等于2,dp[2]找到4\6\8\10,其中最大的dp[4]=2,所以dp[2] = 3,dp[1]后面的都能找到它的倍数,其中最大的dp[2]=3,所以dp[1]=4。到此为止,我们已经找到了最大的共存元素个数,这个时候就需要将其还原了,但是好像少了什么,没错,我找到dp[1]最大了,但是dp[1]是包含哪4个元素?好像找不到了,这就需要在找的过程顺便建立一种联系,可以想象成很多个链表。
1->2->4->8
5->10
3->9
所有dp值大于等于2的元素都将作为起始点指向它的父节点,也就是能整除它的父亲。
结果:68ms
tag:链表、排序
题意:将一个链表按照插入排序的方法从小到达排列。
思路:
1、以4->2->3->1为例,来看看如何使用插入排序。
首先新建一个结果链表,设立一个左边界,然后去从结果链表中找到一个比待插入元素大的位置,将待插入元素插入。
具体来看,先从4开始访问 ,当访问到4的时候,将它加入结果数组中。结果数组中都是有序的,这个时候
结果链表中有一个左边界和元素4,这个时候再访问3的时候,需要遍历结果链表,给它找到应该放的位置,那怎么找呢?就是逐个访问结果链表,如果找到小于我们找的值,就跳到下一个,直到找到一个比插入值大的元素或者找到最后没找到,这里对应的是4,将插入值插入到左边界和4之间。
结果:168ms
第二次刷代码168ms
结果:80ms
tag:链表、排序
题意:nlogn时间,常数空间对链表进行排序。
思路:
1、因为链表直接访问下标不太方便,所以在排序的时候使用快排思想不太容易实现。那么,还要什么思路呢?桶排序不失为一种方法,当时空间复杂度过高,相当于时间复杂换空间复杂,还有哪些常见的排序呢?不难想到归并排序正是我们所想找的。
归并排序主要就是归和并两步骤,归用递归去解决,每次将连表分为前半部分和后半部分。直到平凡情况,即两部分都只有1个元素,这个时候就需要开始并了。
并的思路很简单,逐个比较两部分元素,创建一个新链表,哪边小就将结果加进去,最后肯定会剩下一部分元素,再给接到链表最后,最后返回这整个链表去处理上一层的递归调用。
结果:60ms
今日题目:
1、最大整除子集;2、链表插入排序;
3、链表排序 。
今日摘录:
我愿意深深地扎入生活,吮尽生活的骨髓,过得扎实,简单,把一切不属于生活的内容剔除得干净利落,把生活逼到绝处,用最基本的形式,简单,简单,再简单。——梭罗《瓦尔登湖》
368. Largest Divisible Subset | Difficulty: Medium
Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this subset satisfies: Si % Sj = 0 or Sj % Si = 0.If there are multiple solutions, return any subset is fine.
Example 1:
nums: [1,2,3]
Result: [1,2] (of course, [1,3] will also be ok)
Example 2:
nums: [1,2,4,8]
Result: [1,2,4,8]
tag:数学、DP
题意:从一个集合中去寻找满足集合内部每两个元素都存在非1公约数的子集。
思路:
1、本来想从前往后去找,后来发现不太对劲,又从后往前去找,好像又没找到什么规律。后面一怒之下打了两小时乒乓球加桌球,好像开窍了。
还是看一个栗子加深理解吧,也不举太复杂的栗子,就[0,1,2,3,4,5,6,7,8,9,10]其实本来不应该有0,但是为了表示的方便,暂时加进来,不考虑就是了。
从大到小遍历这个数组,dp[i]中代表以元素i作为结尾的最大集合长度。dp[10] = 1,然后逆推往回求dp[9],从9一直到最后找能被10整除的数字,没这样的不存在,所以dp[9]=1,同理dp[8]=dp[7]=dp[6]=1.到dp[5]的时候,向后找找到了10能整除5,所以dp[5] = 2,同理dp[4]找到8、dp[3]找到6或者9,因为dp[6]=dp[9]=1,所以dp[3]找到他俩中的较大值再加1dp[3]=2,也等于2,dp[2]找到4\6\8\10,其中最大的dp[4]=2,所以dp[2] = 3,dp[1]后面的都能找到它的倍数,其中最大的dp[2]=3,所以dp[1]=4。到此为止,我们已经找到了最大的共存元素个数,这个时候就需要将其还原了,但是好像少了什么,没错,我找到dp[1]最大了,但是dp[1]是包含哪4个元素?好像找不到了,这就需要在找的过程顺便建立一种联系,可以想象成很多个链表。
1->2->4->8
5->10
3->9
所有dp值大于等于2的元素都将作为起始点指向它的父节点,也就是能整除它的父亲。
class Solution { public: vector<int> largestDivisibleSubset(vector<int>& nums) { sort(nums.begin(),nums.end()); vector<int> T(nums.size(),0); vector<int> parent(nums.size(),0); int max=0,maxIdx=0; for(int i=nums.size()-1;i>=0;--i) { for(int j=i;j<nums.size();++j) { if(nums[j]%nums[i]==0 && T[i]<1+T[j]) { T[i] = 1+T[j]; parent[i]=j; if(T[i]>max) { max = T[i]; maxIdx = i; } } } } vector<int> res; for(int i=0;i<max;i++) { res.push_back(nums[maxIdx]); maxIdx = parent[maxIdx]; } return res; } };
结果:68ms
147. Insertion Sort List | Difficulty: Medium
Sort a linked list using insertion sort.tag:链表、排序
题意:将一个链表按照插入排序的方法从小到达排列。
思路:
1、以4->2->3->1为例,来看看如何使用插入排序。
首先新建一个结果链表,设立一个左边界,然后去从结果链表中找到一个比待插入元素大的位置,将待插入元素插入。
具体来看,先从4开始访问 ,当访问到4的时候,将它加入结果数组中。结果数组中都是有序的,这个时候
结果链表中有一个左边界和元素4,这个时候再访问3的时候,需要遍历结果链表,给它找到应该放的位置,那怎么找呢?就是逐个访问结果链表,如果找到小于我们找的值,就跳到下一个,直到找到一个比插入值大的元素或者找到最后没找到,这里对应的是4,将插入值插入到左边界和4之间。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* insertionSortList(ListNode* head) { ListNode res(INT_MIN); while(head) { ListNode*iter = &res; cout<<iter->val<<endl; while(iter->next && iter->next->val <head->val) iter = iter->next; //首先保存下来head的下一个节点,加入head之后好更改head的值 ListNode*next = head->next; //然后准备插入head节点,对head和iter做一个比较看看是插入到前面还是后 head->next = iter->next; iter->next = head; head = next; } return res.next; } };
结果:168ms
第二次刷代码168ms
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* insertionSortList(ListNode* head) { if(head==NULL || head->next==NULL) return head; ListNode*res = new ListNode(INT_MIN); while(head) { ListNode*cur = res; ListNode*next = head->next; while(cur->next && cur->next->val<head->val) cur = cur->next; head->next = cur->next; cur->next = head; head = next; } return res->next; } };
结果:80ms
148. Sort List | Difficulty: Medium
Sort a linked list in O(n log n) time using constant space complexity.tag:链表、排序
题意:nlogn时间,常数空间对链表进行排序。
思路:
1、因为链表直接访问下标不太方便,所以在排序的时候使用快排思想不太容易实现。那么,还要什么思路呢?桶排序不失为一种方法,当时空间复杂度过高,相当于时间复杂换空间复杂,还有哪些常见的排序呢?不难想到归并排序正是我们所想找的。
归并排序主要就是归和并两步骤,归用递归去解决,每次将连表分为前半部分和后半部分。直到平凡情况,即两部分都只有1个元素,这个时候就需要开始并了。
并的思路很简单,逐个比较两部分元素,创建一个新链表,哪边小就将结果加进去,最后肯定会剩下一部分元素,再给接到链表最后,最后返回这整个链表去处理上一层的递归调用。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* sortList(ListNode* head) { if(head==NULL || head->next==NULL) return head; ListNode *h1 = head; ListNode*h2 = head->next->next; while(h2 && h2->next) { h1 = h1->next; h2 = h2->next->next; } h2 = h1->next; h1->next = NULL; return merge(sortList(head),sortList(h2)); } ListNode *merge(ListNode*h1,ListNode*h2) { ListNode *newHead = new ListNode(INT_MIN); ListNode *node =newHead ; while(h1 && h2) { if(h1->val<h2->val) { node->next = h1; node = node->next; h1 = h1->next; } else { node->next = h2; node = node->next; h2 = h2->next; } } if(h1) node->next = h1; else node->next= h2; return newHead->next; } };
结果:60ms