数据结构基础(三)+ 快乐数

移动零

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int ptr1 = 0,ptr2 = 1;
        if(nums.size()<=1){
            return;
        }
        while(ptr2<nums.size()){
            while(nums[ptr2]==0){   //是0则右移到非0位置,但不能超过边界       
                if(ptr2>=nums.size()-1)
                    break;
                ptr2++;
            }
            if(nums[ptr1]==0&&nums[ptr2]!=0){   //是0则交换
                nums[ptr1] = nums[ptr2];
                nums[ptr2] = 0;
            }
            ptr1++;
            if(ptr1>=ptr2)	//ptr1超过ptr2唯一的情况就是前面全是非0数
                ptr2 = ptr1 + 1;
        }
    }
};

虽然写得很烂,但是是4ms,逻辑也算很清晰了。

链表

链表就是每个节点的存储都是动态决定的,而且每个节点都有一个指向下一个节点的指针,由于存储是动态非连续的,因此我们在插入删除节点时能取到O(1)的优秀效果。

链表必备要素:节点,指针(可以有两个,即双向链表)

一些重要的点:

检查成环:使用快慢指针

两个链表的第一个交点:从尾到头搜索即可找到分歧点

下面是翻转链表,挺简单的,但是一定要注意好指向

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head==NULL)
            return NULL;
        ListNode* myhead = head->next;  //直接从第二跳开始,避免死循环
        ListNode* temp = head;  //永远指向前一跳,原先的head位置永远都是前一跳!!!
        while(myhead!=NULL){
            temp->next = myhead->next; //前一跳直接指向下一跳
            myhead-> next = head; //将该节点放在头部
            head = myhead;  //头部变换地址
            myhead = temp->next; //换成之前的下一跳
        }
        return head;
    }
};

下面是旋转链表的代码,关键在于切割:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if(head==NULL||k==0||head->next==NULL)
            return head;
        int size = 1;//链表长度
        ListNode* end = head;//倒数
        while(end->next!=NULL){
            size+=1;
            end=end->next;
        }
        k = size-k%size; //确认切割位点在第几位
        ListNode* end_k = head;//倒数第k
        int i = 0;
        while(++i<k)
            end_k = end_k->next;
        end->next = head;
        head = end_k->next;
        end_k->next = NULL;
        return head;
    }
};

HASH

hash是一种映射关系,我们可以通过hash将大范围的数据缩在制定范围的桶里,还可以把内容映射成键值,在O(1)时间内找到目标。简单来说,visit数组就是最简单的一对一的hash映射。

class MyHashSet {
private:
    bool a[1000100];
public:
    /** Initialize your data structure here. */
    MyHashSet() {
        for(int i=0;i<1000100;i++)
            a[i] = false;
    }
    
    void add(int key) {
        a[key] = true;
    }
    
    void remove(int key) {
        a[key] = false;
    }
    
    /** Returns true if this set contains the specified element */
    bool contains(int key) {
        return a[key];
    }
};

上面是最简单的,但是实际情况中不会这么用。。。。

总结

c++ hash库调用方法:

unordered_set<int> hashset;

hashset.insert(2);

hashset.erase(2);

hashset.count(2)

vector清空方法 vector<int>().swap(nums);

发布了23 篇原创文章 · 获赞 0 · 访问量 556

猜你喜欢

转载自blog.csdn.net/CSDN_Yong/article/details/104882553