LC第十天

深拷贝!

  • 暴力法 直接AC ,而且效率还不错

  • 哈希表 map用的太妙了

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/
class Solution {
public:
    Node* copyRandomList(Node* head) {
    
    Node* pre=nullptr;
    Node* cur=head;
    if(head==nullptr)
    {
        return pre;
    }
    //复制val和next
    Node* new_node=new Node(cur->val);
    pre=new_node;
    cur=cur->next;
    Node* res=pre;
    while(cur!=nullptr)
    {
        new_node=new Node(cur->val);
        pre->next=new_node;
        cur=cur->next;
        pre=pre->next;
    }
    //复制random
    cur=head;
    pre=res;
    while(cur!=nullptr)
    {   
        Node* go=head;
        Node* go1=res;
        while(go!=nullptr)
        {
            if(cur->random == go)
            {
                pre->random=go1;
                break;
            }
            go=go->next;
            go1=go1->next;
        }
        cur=cur->next;
        pre=pre->next;
    }

    return res;
    }
};

因为第二次循环 的时候查找很费劲,所以用哈希表很舒服!

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/
class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(head == nullptr) return nullptr;
        Node* cur = head;
        unordered_map<Node*, Node*> map;
        //  复制各节点,并建立 “原节点 -> 新节点” 的 Map 映射
        while(cur != nullptr) {
            map[cur] = new Node(cur->val);
            cur = cur->next;
        }
        cur = head;
        //  构建新链表的 next 和 random 指向
        while(cur != nullptr) {
            map[cur]->next = map[cur->next];
            map[cur]->random = map[cur->random];
            cur = cur->next;
        }
        //  返回新链表的头节点
        return map[head];
    }
};

 



递归!!中序遍历的理解要加深

二叉搜索树的 中序遍历是递增的排序序列!

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* left;
    Node* right;

    Node() {}

    Node(int _val) {
        val = _val;
        left = NULL;
        right = NULL;
    }

    Node(int _val, Node* _left, Node* _right) {
        val = _val;
        left = _left;
        right = _right;
    }
};
*/
class Solution {
public:
    Node* pre,* head;
    void inorder(Node* cur)
    {
        if(cur==nullptr)
        return ;

        inorder(cur->left);
        if(pre!=nullptr)
        pre->right=cur;
        else
        head=cur;
        cur->left=pre;
        pre=cur;
        inorder(cur->right);
    }

    Node* treeToDoublyList(Node* root) {
      if(root==nullptr)
    return root;
    inorder(root);
    head->left=pre;
    pre->right=head;
    return head;
    }
};


全排列问题,DFS+剪枝

  • ps:之前做过,但没有很熟练,这次还是不会,有时间再多做几次(现在看代码很简单)
  • 需要注意这里 set的妙用,主要是用 find();
  • 还要注意这个 swap和for 的搭配
  • 具体细节还可以看《LC第一天》前两题
class Solution {
public:
    vector<string> permutation(string s) {
    dfs(s,0);
    return res;
    }
private:
    vector<string> res;
    void dfs(string s,int index)
    {
        if(index==s.size()-1)
        {   
            res.push_back(s);
            return;
        }

        set<int> st;
        for(int i=index;i<s.size();++i)
        {
            if(st.find(s[i])!=st.end())//重复,因此剪枝
            continue;
            st.insert(s[i]);
            swap(s[i],s[index]);    //交换,将s[i]固定在Index的位置
            dfs(s,index+1);         //递归下一位
            swap(s[i],s[index]);    //恢复交换
        }
    }
};


三种解法:

  • 哈希表统计
  • 数组排序法
  • 摩尔投票法:核心观念正负抵消;关键在于题意 这个数比一半都多。(最佳解法)

class Solution {
public:
    int majorityElement(vector<int>& nums) {
    int res=nums[0];
    int times=1;
    for(int i=1;i<nums.size();++i)
    {
        if(nums[i]==res)
        ++times;
        else
        --times;
        if(times==0)
        {
            res=nums[i];
            times=1;
        }
    }
    return res;
    }
};


 

经典:topK 问题,很容易出面试题

  • 自己实现 快速排序 O(nlogn) 重点是要会自己手撕快排!

  • 基于快排的数组划分,完成topK就,不排完 O(n)

  • 最大堆 O(nlogk)  红黑树什么的

快速排序,两个核心:哨兵划分+递归!

class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        quickSort(arr,0,arr.size()-1);
        vector<int> res;
        res.assign(arr.begin(),arr.begin()+k);
        return res;
    }
private:
    void quickSort(vector<int>& arr,int left,int right)
    {
        //子数组长度为1时终止递归
        if(left>=right) return;
        //哨兵划分操作(以arr[left]作为基准数)
        int i=left,j=right;
        while(i<j)
        {
            while(i<j && arr[j]>=arr[left]) j--;
            while(i<j && arr[i]<=arr[left]) i++;
            swap(arr[i],arr[j]);
        }
        swap(arr[i],arr[left]);
        //递归左(右)子数组执行哨兵划分
        quickSort(arr,left,i-1);
        quickSort(arr,i+1,right);
    }
};

 基于快排的数组划分

class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        if(k>=arr.size()) return arr;
        return quickSort(arr,k,0,arr.size()-1)
    }
private:
    vector<int> quickSort(vector<int>&arr,int k,int left,int right)
    {
        int i=left,j=right;
        while(i<j)
        {
            while(i<j && arr[j]>=arr[left]) --j;
            while(i<j && arr[i]<=arr[left]) ++i;
            swap(arr[i],arr[j]);
        }
        swap(arr[i],arr[left]);
        if(i>k) return quickSort(arr,k,left,i-1);
        if(i<k) return quickSort(arr,k,i+1,right);
        vector<int> res;
        res.assign(arr.begin(),arr,begin()+k);
        return res;
    }
};

 C++中 优先队列 为大根堆!可以拿来直接用

class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        vector<int> vec(k,0);
        if(k==0) return vec;
        priority_queue<int> Q;
        for(int i=0;i<k;++i)
        {
            Q.push(arr[i]);
        }
        for(int i=k;i<arr.size();++i)
        {
            if(Q.top()>arr[i])
            {
                Q.pop();
                Q.push(arr[i]);
            }
        }
        for(int i=0;i<k;++i)
        {
            vec[i]=Q.top();
            Q.pop();
        }
        return vec;
    }
};

 上述2、3方案对比:

  • 2方案需要修改原数组,如果原数组不能修改了话,还需要拷贝一份数组,空间复杂度就上去了!

  • 3方案,如果把数据看成输入流的话,使用堆的方法是来一个处理一个,不需要保存数据,只需要保存 k 个元素的最大堆。而快速选择的方法需要先保存下来所有的数据,再运行算法。当数据量非常大的时候,甚至内存都放不下的时候,就麻烦了。所以当数据量大的时候还是用基于堆的方法比较好。




动态规划!

代码 不是严格 按照上面的思路,但本质上是一样的! 

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int res=nums[0];
        int cur=nums[0];
        for(int i=1;i<nums.size();++i){
            cur=cur+nums[i];
            if(cur<nums[i])
            cur=nums[i];
            res=max(res,cur);
        }
        return res;
    }
};


迭代+求整/求余

class Solution {
public:
    int findNthDigit(int n) {
        int digit=1;
        long long start=1;
        long long count=9;
        //求出是几位数的范围
        while(n>count)
        {
            n-=count;
            digit+=1;
            start*=10;
            count=digit*start*9;
        }
        //求出是哪个数
        long long num=start+(n-1)/digit;
        //确定所求数位在num的哪一数位
        vector<int> s;
        while(num)
        {
            s.push_back(num%10);
            num=num/10;
        }
        int len=s.size();
        int res=s[len-(n-1)%digit-1];
        return res;
    
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值