leetcode题解日练--2016.7.23

日练三题,冰冻三尺非一日之寒。

今日题目:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值