【Notes15】剑指offer_31-40题


31.栈的压入、弹出序列

在这里插入图片描述

//java版
class Solution {
    
    
    public boolean validateStackSequences(int[] pushed, int[] popped) {
    
    
        Stack<Integer> temp = new Stack<>();
        int i = 0;
        for(int num : pushed)
        {
    
    
            temp.push(num);//入栈
            //模拟出栈
            while(!temp.isEmpty() && temp.peek() == popped[i])
            {
    
    
                temp.pop();
                i ++;
            }
        }
        return temp.isEmpty();
    }
}
//C++版
class Solution {
    
    
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
    
    
        if(pushV.size() != popV.size()) return false;
        
        stack<int> stk;
        int i = 0;
        
        //stk.top() == popV[i]   stk.pop()
        //stk.top() != popV[i]   stk.push(x);
        for(auto x : pushV)
        {
    
    
            stk.push(x);
            while(stk.size() && stk.top() == popV[i])
            {
    
    
                stk.pop();
                i ++;
            }
        }
        return stk.empty();
    }
};

32.从上到下打印二叉树

在这里插入图片描述

//java版
class Solution {
    
    
    public int[] levelOrder(TreeNode root) {
    
    
        if(root == null) return new int[0];

        ArrayList<Integer> ans = new ArrayList<>();
        //队列操作  保存根节点
        Queue<TreeNode> q = new LinkedList<>();
        q.add(root);
        while(!q.isEmpty())
        {
    
    
            //根结点
            TreeNode r = q.poll();
            ans.add(r.val);
            //左子树
            if(r.left != null) q.add(r.left);
            //右子树
            if(r.right != null) q.add(r.right);
        }
        int[] res = new int[ans.size()];
        for(int i = 0; i < ans.size(); i ++)
            res[i] = ans.get(i);
        return res;
    }
}
//C++版
class Solution {
    
    
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
    
    
        vector<int> res;
        if(!root) return res;
        
        //非空
        queue<TreeNode*> q;
        q.push(root);
        
        //bfs 广度优先遍历
        while(q.size())
        {
    
    
            auto t = q.front();
            q.pop();
            res.push_back(t -> val);
            if(t -> left) q.push(t -> left);
            if(t -> right) q.push(t -> right);
        }
        
        return res;
    }
};

33.二叉搜索树的后序遍历序列

在这里插入图片描述

//java版
class Solution {
    
    
    public boolean verifyPostorder(int[] postorder) {
    
    
        //左<根<右 二叉检索树
        //后序遍历 
        //左右根
        //递归
        return dfs(postorder, 0, postorder.length - 1);
    }
    public boolean dfs(int[] arr, int l, int r)
    {
    
    
        if(l >= r) return true;//遍历到最后 都是true
        //r对应 当前子树 根节点
        //找到左右子树的临界点
        int p = l;
        while(arr[p] < arr[r]) p ++;
        int m = p;
        while(arr[p] > arr[r]) p ++;
        return (p == r) && dfs(arr, l, m - 1) && dfs(arr, m, r - 1);
    }
}
//C++版
class Solution {
    
    
public:
    //后续遍历  左右根
    //二叉搜索树特点  左孩子 < 父亲结点 < 右孩子
    //左右根    
    //数组最后一个数字就是根节点/父亲结点 
    //左右子树分界点  与根节点相比较
    vector<int> seq;
    bool VerifySquenceOfBST(vector<int> sequence) {
    
    
        seq = sequence;
        if(seq.empty()) return false;
        return dfs(0, seq.size() - 1);
    }
    
    bool dfs(int l, int r)
    {
    
    
        if(l >= r) return true;
        
        //父亲结点
        int father = seq[r];
        //左子树 都小于
        int k = l;
        while(k < r && seq[k] < father) k ++;
        //右子树 都大于
        for(int i = k; i < r; i ++)
            if(seq[i] < father)
                return false;
        
        return dfs(l, k - 1) && dfs(k, r - 1);
    }
};

34.二叉树中和为某一值的路径

在这里插入图片描述
在这里插入图片描述

//java版
class Solution {
    
    
    //前序遍历 根左右
    LinkedList<List<Integer>>  res = new LinkedList<>();//所有路径
    LinkedList<Integer> path = new LinkedList<>();//单条路径
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
    
    
        //递归函数
        recur(root, sum);
        return res;
    }
    void recur(TreeNode root, int target){
    
    
        //找到 target = 0时候的叶节点
        if(root == null) return;
        path.add(root.val);
        target -= root.val;
        if(target == 0 && root.left == null && root.right == null)
            res.add(new LinkedList(path));
        recur(root.left, target);
        recur(root.right, target);
        //每次结束后 path必须清空
        path.removeLast();
    }
}
//C++版
class Solution {
    
    
public:
    vector<vector<int> > res;
    vector<int> path;
    vector<vector<int> > FindPath(TreeNode* root,int sum) {
    
    
        dfs(root, sum);
        return res;
    }
    
    void dfs(TreeNode* root,int sum)
    {
    
    
        if(!root) return;
        path.push_back(root -> val);
        sum -= root -> val;
        //sum == 0 且找到了叶节点  确定一条路径
        if(!sum && !root -> left && !root -> right) res.push_back(path);
        
        dfs(root -> left, sum);
        dfs(root ->right, sum);
        path.pop_back();
    }
};

35.复杂链表的复制

在这里插入图片描述

//java版
class Solution {
    
    
    public Node copyRandomList(Node head) {
    
    
        if(head == null)
            return null;
        
        copy(head);//复制结点
        copyrandom(head);//复制random指针
        return divide(head);//分离出来
    }
    private void copy(Node head){
    
    
        while(head != null)
        {
    
    
            Node clone = new Node(head.val);
            Node nextNode = head.next;
            head.next = clone;
            clone.next = nextNode;
            head = clone.next;
        }
    }
    private void copyrandom(Node head){
    
    
        while(head != null){
    
    
            Node clone = head.next;
            if(head.random != null)
            {
    
    
                Node randomnode = head.random;
                clone.random = randomnode.next;
            }
            head = clone.next;
        }
    }
//7  8 9 10
//7 7’ 8 8‘ 9 9‘ 10 10’
    private Node divide(Node head)
    {
    
    
        Node cloneNode = head.next;
        Node cloneHead = cloneNode;
        head.next = cloneNode.next;
        head = head.next;
        while(head != null)
        {
    
    
            cloneNode.next = head.next; // 8'
            head.next = head.next.next;//8 9
            head = head.next;
            cloneNode = cloneNode.next;
        }
        return cloneHead;
    }
}
//C++版
class Solution {
    
    
public:
    RandomListNode* Clone(RandomListNode* head)
    {
    
    
        
        //1. 复制每个结点 next
            //在两个结点之间新建一个结点  复制前驱
        for(auto p = head; p;)
        {
    
    
            auto newp = new RandomListNode(p -> label);
            //在p  和  p -> next之间插入newp
            auto temp = p -> next;
            p -> next = newp;
            newp -> next = temp;
            p = temp;
        }
        
        //random
        //a -> next -> ramdom = a -> random -> next;
        for(auto p = head; p; p = p -> next -> next)
        {
    
    
            if(p -> random)
                p -> next -> random = p -> random -> next;
        }
        
        auto dummy = new RandomListNode(-1);
        
        auto cur = dummy;
        for(auto p = head; p; p = p -> next)
        {
    
    
            cur -> next = p -> next;//A'
            cur = cur -> next;
            p -> next = p -> next -> next;
        }        
        return dummy -> next;
    }
};

36.二叉搜索树与双向链表

在这里插入图片描述

//java版
class Solution {
    
    
    Node pre,head;
    public Node treeToDoublyList(Node root) {
    
    
        if(root == null) return null;
        dfs(root);//左根右 递增
        //头尾结点处理一下
        head.left = pre;
        pre.right = head;
        return head;
    }
    private void dfs(Node cur){
    
    
        if(cur == null) return;
        //左子树
        dfs(cur.left);
        //根结点
        //left right指针
        if(pre != null) pre.right = cur;
        else head = cur;
        cur.left = pre;
        pre = cur;
        //右子树
        dfs(cur.right);
    }
}
//C++版
class Solution {
    
    
public:
    TreeNode* Convert(TreeNode* root)
    {
    
    
        if(!root) return NULL;
        auto pairs = dfs(root);
        return pairs.first;
    }
    
    pair<TreeNode*,TreeNode*> dfs(TreeNode* root)
    {
    
    
        if(!root -> left && ! root -> right) return {
    
    root, root};
        if(root -> left && root -> right)
        {
    
    
            auto lsides = dfs(root -> left), rsides = dfs(root -> right);
            //左边返回
            //{1,2}  2 ——> root   root -> 2
            lsides.second -> right = root;
            root -> left = lsides.second;
            //右边返回
            //{1,2}  1——> root  root -> 1
            rsides.first -> left = root;
            root -> right = rsides.first;
            return {
    
    lsides.first, rsides.second};
        }
        //只有左子树
        if(root -> left)
        {
    
    
            auto lsides = dfs(root -> left);
            //左边返回
            //{1,2}  2 ——> root   root -> 2
            lsides.second -> right = root;
            root -> left = lsides.second;
           
            return {
    
    lsides.first, root};
        }
        //只有右子树
        if(root -> right)
        {
    
    
            auto rsides = dfs(root -> right);
            //右边返回
            //{1,2}  1——> root  root -> 1
            rsides.first -> left = root;
            root -> right = rsides.first;
            return {
    
    root, rsides.second};
        }
    }
};

37.序列化二叉树

在这里插入图片描述

//java版
public class Codec {
    
    
    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
    
    
        if(root == null) return "[]";
        //序列化为 "[1,2,3,null,null,4,5]"
        StringBuilder res = new StringBuilder("[");
        Queue<TreeNode> q = new LinkedList<>();
        q.add(root);
        while(!q.isEmpty())
        {
    
    
            TreeNode t = q.poll();
            if(t != null)
            {
    
    
                res.append(t.val + ",");
                q.add(t.left);
                q.add(t.right);
            }
            else
                res.append("null,");
        }
        res.append("]");
        return res.toString();
    }
    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
    
    
        if(data.equals("[]")) return null;
        String[] vals = data.substring(1,data.length()-1).split(",");
        TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
        Queue<TreeNode> q = new LinkedList<>();
        q.add(root);
        int i = 1;
        while(!q.isEmpty())
        {
    
    
            TreeNode node = q.poll();
            if(!vals[i].equals("null")){
    
    
                node.left = new TreeNode(Integer.parseInt(vals[i]));
                q.add(node.left);
            }
            i ++;
            if(!vals[i].equals("null")){
    
    
                node.right = new TreeNode(Integer.parseInt(vals[i]));
                q.add(node.right);
            }
            i ++;
        }
        return root;
    }
}
//C++版
class Solution {
    
    
public:
    char* Serialize(TreeNode *root) {
    
        
        string res;
        dfs1(root, res);
        char* p = new char[res.size() + 1];
        strcpy(p, res.c_str());
        
        return p;
    }
    
    void dfs1(TreeNode* root, string &res)
    {
    
    
        if(!root)
        {
    
    
            //#
            res += "#,";
            return;
        }
        
        res += to_string(root -> val) + ",";
        dfs1(root -> left, res);
        dfs1(root -> right, res);
    }
    
    //反序列化
    TreeNode* Deserialize(char *str) {
    
    
        int idx = 0;
        return dfs2(str, idx);
    }
    
    TreeNode* dfs2(char* str, int &idx)
    {
    
    
        //确定长度  23  长度2  3 长度1
        int len = idx;
        while(str[len] != ',') len ++;
        //空结点
        if(str[idx] == '#')
        {
    
    
            idx = len + 1;
            return NULL;
        }
        //非空结点
        //计算数值
        int num = 0;
        //考虑符号+-
        int sign = 1;
        if(idx < len && str[idx] == '-') sign = -1, idx ++;
        // ‘234’
        for(int i = idx; i < len; i ++) num = num * 10 + str[i] - '0';
        num *= sign;
        //idx走到下一个数字
        idx = len + 1;
        //构建树
        auto root = new TreeNode(num);
        root -> left = dfs2(str, idx);
        root -> right = dfs2(str, idx);        
        return root;
    }    
};

38.字符串的排列

在这里插入图片描述

//java版
class Solution {
    
    
    Set<String> res = new HashSet<>();//保存结果
    public String[] permutation(String s) {
    
    
        if(s == null) return new String[]{
    
    };
        boolean[] visited = new boolean[s.length()];
        dfs(s,"",visited);
        return res.toArray(new String[res.size()]);
    }
    private void dfs(String s, String ch, boolean[] visited){
    
    
        if(s.length() == ch.length())
        {
    
    
            res.add(ch);//abc
            return;
        }
        for(int i = 0; i < s.length(); i ++)
        {
    
    
            char temp = s.charAt(i);
            if(visited[i]) continue;
            visited[i] = true;
            dfs(s, ch + String.valueOf(temp), visited);
            visited[i] = false;
        }
    }
}
//C++版
class Solution {
    
    
public:
    vector<string> res;
    string path;
    
    vector<string> Permutation(string str) {
    
    
        if(str == "") return res;  //[""] []
        //全排列
        //可能重复字母 靠在一起 好判断
        sort(str.begin(),str.end());
        path.resize(str.size());
        //全排列函数
        dfs(str, 0, 0, 0);
        
        //字典顺序
        sort(res.begin(), res.end());
        return res;
    }
    
    void dfs(string &str, int idx, int start, int state)
    {
    
    
        //已经找到一个排列
        if(idx == str.size())
        {
    
    
            res.push_back(path);
            return;
        }
        //单个排列没有排完
        //相同字母而言 前后关系  
        //可能重复排序
        //通过控制相对顺序不变确保不重复
        if(idx == 0 || str[idx] != str[idx - 1]) start = 0;
        //顺序往后
        for(int i = start; i < str.size(); i ++)
            if(!(state >> i & 1))
            {
    
    
                path[i] = str[idx];
                dfs(str, idx + 1, i + 1, state + (1 << i));
            }
    }
};

39.数组中出现次数超过一半的数字

在这里插入图片描述

//java版
class Solution {
    
    
    public int majorityElement(int[] nums) {
    
    
        int val = -1, cnt = 0;
        for(int num : nums)
        {
    
    
            //记录相同数字出现次数
            //当前数字 == val cnt ++
            //cnt == 0 val更新当前的
            //最后肯定有cnt >=1 val
            if(num == val)
                cnt ++;
            else{
    
    
                //2 2 1 1 1
                if(cnt >= 1) cnt --;
                else{
    
    
                    val = num;
                    cnt = 1;
                }
            }
        }
        return val;
    }
}
//C++版
class Solution {
    
    
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
    
    
        int val, cnt = 0;
        for(auto x : numbers)
        {
    
    
            if(val == x)
                cnt ++;
            else{
    
    
                if(cnt) cnt --;
                else{
    
    
                    val = x;
                    cnt = 1;
                }
            }
        }
        
        cnt = 0;
        for(auto x : numbers)
        {
    
    
            if(x == val)
                cnt ++;
        }
        
        if(cnt * 2 > numbers.size())
            return val;
        
        return 0;
        
    }
};

40.最小的k个数.txt

在这里插入图片描述

//java版
class Solution {
    
    
    //快排
    public int[] getLeastNumbers(int[] arr, int k) {
    
    
        if(k == 0 || arr.length == 0)
            return new int[0];
        return qsk(arr,0, arr.length - 1, k - 1);
    }
    private int[] qsk(int[] nums, int l, int r, int k){
    
    
        int j = quicksort(nums, l, r);
        //j k对比得到要不要返回前k小的数组
        if(j == k)
        {
    
    
            return Arrays.copyOf(nums,j + 1);
        }
        //否则 要根据 j  k大小关系进行调整
        return j > k ? qsk(nums,l, j - 1, k) : qsk(nums, j + 1, r, k);
    }


    private int quicksort(int[] nums, int l, int r){
    
    
        int v = nums[l];
        int i = l, j = r + 1;
        while(true)
        {
    
    
            while(++i <= r && nums[i] < v);//i
            while(--j >= l && nums[j] > v);//j
            if(i >= j)
                break;
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
        }
        nums[l] = nums[j];
        nums[j] = v;
        return j;//保证 nums[j] 左边是最小的j个数字
    }
}
//C++版
class Solution {
    
    
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
    
    
        //暴力解答
        /*
        vector<int> res;
        if(k > input.size()) return res;
        
        sort(input.begin(),input.end());
        for(int i = 0; i < k; i ++)
        {
            res.push_back(input[i]);
        }
        
        return res;
        */
        //大根堆 k
        vector<int> res;
        if(k > input.size()) return res;
        priority_queue<int> heap;
        
        //找到最小的k个数字
        for(auto x : input)
        {
    
    
            heap.push(x);
            if(heap.size() > k) heap.pop();
        }
        //从大到小输入
        while(heap.size()) res.push_back(heap.top()), heap.pop();
        //从小到大
        reverse(res.begin(), res.end());        
        return res;        
    }
};

猜你喜欢

转载自blog.csdn.net/weixin_43435675/article/details/107240368