剑指Offer-6-从尾到头打印链表

第一种思路是用栈

  1. 遍历链表,将每一个节点值压入栈中
  2. 弹栈,逆向输出整个链表
class Solution {
public:
    vector<int> reversePrint(ListNode* head) {
        vector<int> result;
        // 将链表的每一个节点值都压入栈中
        stack<int> st;
        // 其实我不确定下面的写法是不是会有问题
        for(ListNode* i = head;i!=nullptr;i+1){
            st.push(i->val);
        }
        // 弹出栈中元素并放入数组中
        while(!st.empty()){
            result.push_back(st.top());
            st.pop();
        }
        return result;
    }
};

但是两次遍历很明显时间效率不高甚至超时(事实上除了空都超时了)

第二种思路则是,利用递归

class Solution {
public:
    vector<int> reversePrint(ListNode* head) {
        vector<int> result;
        // 每次访问一个节点时,先输出它的下一个节点
        next(head,result);
        return result;
    }
    void next(ListNode* head,vector<int> &result){
        if(head!=nullptr){
            if(head->next!=nullptr){
                next(head->next,result);
            }
            result.push_back(head->val);
        }
    }
};

但总感觉应该还有更好的解法
以及…优化,当然如果能解决返回值的问题的话就不用单独再写一个方法了
看到评论里有一个这样的写法

public:
    vector<int> reversePrint(ListNode* head) {
        if(!head)
            return {};
        vector<int> a=reversePrint(head->next);
        a.push_back(head->val);
        return a;
    }
};

看起来非常简洁,但其实不太好——在于每一次的递归都会创建一个局部变量数组,如果链表长了,递归层级多了,很难说不会超内存

执行用时没有减少,而内存消耗增加了

这里还有一种”预分配+逆向指针“的解法

class Solution {
public:
    vector<int> reversePrint(ListNode* head) {
        ListNode* node = head;
        size_t count = 0;
        // 这个循环是在计数链表长度
        while (node != nullptr) {
            ++count;
            node = node->next;
        }
        vector<int> nums(count);// 预分配数组长度
        node = head;
        // rbegin()方法是获取反向迭代器
        for(auto i = nums.rbegin(); i != nums.rend(); ++i){
            *i=node->val;
            node=node->next;
        }
        return nums;
    }
};


确实效果更好了


2023/1/31

	vector<int> reversePrint(ListNode* head) {
		// 我的第一想法是遍历然后用栈来实现反转输出,但是很明显这样需要额外的空间
		// 或者不使用物理栈,而是使用方法栈来实现,也就是递归栈
		// 我写的“预分配+反向指针”不会是遍历一遍链表获取长度设置给数组,然后反向填充数组吧?
		// 对的,三种思路都已经想出来了,我觉得吧…都不完美
		// 第一种需要额外的空间,第二种题目链表最长是10000,感觉方法栈太深了不好,第三种需要遍历两次链表
		// 非要选一个选三
		int count =0;
		// 避免修改原指针
		ListNode* head2 = head;
		while (head2) {
			count++;
			head2 = head2->next;
		}
		head2 = head;
		vector<int> res(count);
		for (int i = count - 1; i >= 0; i--) {
			res[i] = head2->val;
			head2 = head2->next;
		}
		return res;
	}
posted @ 2022-04-27 11:43  YaosGHC  阅读(33)  评论(0)    收藏  举报