【Notes17】剑指offer_51-60题


51.数组中的逆序对

在这里插入图片描述

//java版
class Solution {
    
    
    //归并排序
    public int reversePairs(int[] nums) {
    
    
        int len = nums.length;
        if(len < 2)//逆序对要求两个数字以上
            return 0;
        int[] temp = new int[len];
        return mergeSort(nums, 0, len - 1, temp);
    }
    private int mergeSort(int[] nums, int left, int right, int[] temp){
    
    
        //递归终止条件
        if(left >= right)
            return 0;
        int mid = left + (right - left) / 2;//防止溢出
        //[left, mid]
        int leftPairs = mergeSort(nums, left, mid, temp);
        //[mid + 1, right]
        int rightPairs = mergeSort(nums, mid +1, right, temp);
        //[left mid] [mid + 1  right]
        if(nums[mid] <= nums[mid + 1]){
    
    
            return leftPairs + rightPairs;
        }
        //跨区间的逆序对
        int crossPairs = mergeSortCross(nums, left, mid, right, temp);
        return leftPairs + rightPairs + crossPairs;
    }
    private int mergeSortCross(int[] nums, int left,int mid, int right, int[] temp){
    
    
        for(int i = left; i <= right; i ++)
            temp[i] = nums[i];
        
        int i = left;
        int j = mid + 1;
        //[left i mid]  [mid + 1 j  right]
        // mid - i + 1个逆序对
        int count = 0;
        for(int k = left; k <= right; k ++){
    
    
            if(i == mid  + 1){
    
    
                nums[k] = temp[j];
                j ++;
            }else if(j == right + 1){
    
    
                nums[k] = temp[i];
                i ++;
            }else if(temp[i] <= temp[j]){
    
    
                nums[k] = temp[i];
                i ++;
            }else{
    
    
                nums[k] = temp[j];
                j ++;
                count += mid - i + 1;
            }
        }
        return count;
    }
}
//C++版
class Solution {
    
    
public:
    
    int merge(vector<int> &nums, int l, int r)
    {
    
    
        //[              ]
        //[  i   mid][mid + 1    j   ]
        // mid - i + 1
        if(l >= r) return 0;
        int mid = (l + r) / 2;
        int res = (merge(nums, l, mid) + merge(nums, mid + 1, r)) % 1000000007;
        int i = l, j = mid + 1;
        vector<int> temp; //记录当前归并时候最终有序的数组
        //归并的过程
        while(i <= mid && j <= r)
        {
    
    
            if(nums[i] <= nums[j]) temp.push_back(nums[i ++]);
            else{
    
    
                //逆序对
                temp.push_back(nums[j ++]);
                (res += mid - i + 1) %= 1000000007;
            }
        }
        //存在某个区间没有比较完毕,直接push
        while(i <= mid) temp.push_back(nums[i ++]);
        while(j <= r) temp.push_back(nums[j ++]);
        
        i = l;
        for(auto x : temp) nums[i ++] = x;
        
        return res;
    }
    
    
    int InversePairs(vector<int> data) {
    
    
        return merge(data, 0, data.size() - 1);
    }
};

52.两个链表的第一个公共节点

在这里插入图片描述

//java版
public class Solution {
    
    
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    
    
        ListNode idxA = headA;
        ListNode idxB = headB;
        while(idxA != idxB) {
    
    
            if (idxA == null) idxA = headB;
            else idxA = idxA.next;
            if (idxB == null) idxB = headA;
            else idxB = idxB.next;
        }
        return idxA;
    }
}
//C++版
class Solution {
    
    
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
    
    
        auto p = pHead1, q = pHead2;
        while(p != q)
        {
    
    
            if(p) p = p -> next;
            else p = pHead2;
            
            if(q) q = q -> next;
            else q = pHead1;
        }
        
        return p;
    }
};

53.在排序数组中查找数字 I

在这里插入图片描述

//java版
class Solution {
    
    
    public int search(int[] nums, int target) {
    
    
        //找到target所在位置 start
        //找到target + 1 所在位置 end
        //end - start + (1/0)
        if(nums == null || nums.length == 0)
            return 0;
        
        int start = binarySearch(nums, target), end = binarySearch(nums, target + 1);
        return end - start + (nums[end] == target   1 : 0);
    }
    //二分
    private int binarySearch(int[] nums, int tar){
    
    
        int l = 0, r = nums.length - 1;
        while(l < r){
    
    
            int mid = l + (r - l) / 2;
            //[l  mid] [mid + 1 r]
            if(nums[mid] < tar)
                l = mid + 1;
            else
                r = mid;
        }
        return l;
    }
}

//C++版
class Solution {
    
    
public:
    int getMissingNumber(vector<int>& nums) {
    
    
        if(nums.empty()) return 0;
        //二分 log n
        int l = 0, r = nums.size() - 1;
        
        while(l < r)
        {
    
    
            int mid = l + r >> 1;
            if(nums[mid] != mid) r = mid;
            else l = mid + 1;
        }
        
        //如果缺失的是最后一个数字,需要 r++
        if(nums[r] == r) r++;
        
        return r;
    }
};

0~n-1中缺失的数字
在这里插入图片描述

//java版
class Solution {
    
    
    public int missingNumber(int[] nums) {
    
    
        //nums[i]  i
        //二分
        if(nums == null || nums.length == 0)
            return 0;
        
        //二分
        int l = 0, r = nums.length - 1;
        while(l < r){
    
    
            int mid = l + (r - l) / 2;
            if(nums[mid] != mid) 
                r = mid;
            else
                l = mid + 1;
        }
        //[0 1 2] 3
        if(nums[r] == r)
            r ++;
            
        return r;
    }
}
//C++版
class Solution {
    
    
public:
    int GetNumberOfK(vector<int> data ,int k) {
    
    
        //二分
        //left 左边 < k  右边 >=k
        //right 左边 <=k 右边 > k
        //right - left + 1
        if(data.empty()) return 0;
        //二分
        int l = 0, r = data.size() - 1;
        //找左端点
        while(l < r)
        {
    
    
            int mid = (l + r) / 2;
            if(data[mid] < k) l = mid + 1;
            else r = mid;
        }
        
        if(data[l] != k) return 0;
        int left = l;
        
        //找右端点
        l = 0, r = data.size() - 1;
        while(l < r)
        {
    
    
            int mid = (l + r + 1) / 2;
            if(data[mid] <= k) l = mid;
            else r = mid - 1;
        }
        
        int right = r;
        
        return right - left + 1;
    }
};

54.二叉搜索树的第k大节点

在这里插入图片描述

//java版
class Solution {
    
    
    //中序序列 递增  左根右
    //中序序列反过来  递减
    int k1, res;
    public int kthLargest(TreeNode root, int k) {
    
    
        k1 = k;
        dfs(root);
        return res;
    }
    private void dfs(TreeNode root){
    
    
        if(root == null || k1 == 0) return;
        //右子树
        dfs(root.right);
        //根节点
        if(--k1 == 0) res = root.val;
        //左子树
        dfs(root.left);
    }
}
//C++版
class Solution {
    
    
public:
    TreeNode* res = NULL;
    
    TreeNode* KthNode(TreeNode* root, int k)
    {
    
    
        dfs(root, k);
        return res;
    }

    void dfs(TreeNode* root, int &k)
    {
    
    
        if(!root) return;
        //中序遍历 左根右
        dfs(root -> left, k);
        //根
        k --;
        if(k == 0) res = root;
        //右
        if(k > 0) dfs(root -> right, k);
    }
};

55.二叉树的深度

在这里插入图片描述

//java版
class Solution {
    
    
    public int maxDepth(TreeNode root) {
    
    
        if(root == null) 
            return 0;
        
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        return left>right   left + 1 : right + 1;
    }
}
//C++版
class Solution {
    
    
public:
    int TreeDepth(TreeNode* root)
    {
    
    
        //递归
        //max(left, right) + 1
        if(!root) return 0;
        return max(TreeDepth(root -> left), TreeDepth(root -> right)) + 1;
    }
};

平衡二叉树
在这里插入图片描述

//java版
class Solution {
    
    
    public int treeDepth(TreeNode root) {
    
    
        if(root ==null)return 0;
        int a = treeDepth(root.left);
        int b = treeDepth(root.right);
        return a>b a+1:b+1;
    }
    public boolean isBalanced(TreeNode root) {
    
    
         if (root == null) {
    
    
            return true;
        }
        int left = treeDepth(root.left);
        int right = treeDepth(root.right);
        return Math.abs(left - right) > 1   false : true && isBalanced(root.left) && isBalanced(root.right);
    }
}
//C++版
class Solution {
    
    
public:
    bool res = true;
    bool IsBalanced_Solution(TreeNode* root) {
    
    
        dfs(root);
        return res;
    }
    
    int dfs(TreeNode* root)
    {
    
    
        if(!root) return 0;
        int left = dfs(root -> left), right = dfs(root -> right);
        if(abs(left - right) > 1) res = false;
        return max(left, right) + 1;
    }
};

56.数组中数字出现的次数

在这里插入图片描述

//java版
class Solution {
    
    
    //异或
    // 1 ^ 1 = 0
    // A ^ 0 = A
    public int[] singleNumbers(int[] nums) {
    
    
        int sum = 0;//异或 first ^ second
        for(int x : nums)
            sum ^= x;
        //sum = first ^ second
        //二进制中某一位  1  0 不同
        //找到sum的二进制中 1 所在的那个位置
        int index = 0;
        while((sum >> index & 1) == 0) index ++;//找到了位置
        int first = 0;
        for(int x : nums)
            if((x >> index & 1) == 0) first ^= x;
        //first已经找到了
        int second = sum ^ first;
        // d = a ⊕ b ⊕ c 可以推出 a = d ⊕ b ⊕ c.
        return new int[]{
    
    first, second};
    }
}
//C++版
class Solution {
    
    
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
    
    
        //异或
        //^   x^x = 0
        // x ^ 0  = x
        // x ^ y = z
        int sum = 0;//num1^ num2
        for(auto x : data) sum ^= x; 
        //怎么拆分
        //二进制表示中一定有一位存在不同  1  0
        int k = 0;
        *num1 = 0;
        while(!(sum >> k & 1))  k ++;//通过第k位是否为1分组
        for(auto x : data)
            if(x >> k & 1)
                *num1 ^= x;//num1
        
        *num2 = sum ^ *num1;// num1^num2^num1 = num2
    }
};

在这里插入图片描述

//java版
class Solution {
    
    
    public int singleNumber(int[] nums) {
    
    
        int[] count = new int[32];
        for(int num : nums)
            for(int i = 0; i < 32 ; i ++){
    
    
                count[i] += num & 1;
                num >>= 1;
            }
        int res = 0, mod = 3;
        for(int i = 0; i < 32; i ++){
    
    
            res <<= 1;
            res += count[31 - i] % mod;
        }
        return res;
    }
}
//C++版

57.和为s的两个数字

在这里插入图片描述

//java版
class Solution {
    
    
    public int[][] findContinuousSequence(int target) {
    
    
        List<int[]> re = new ArrayList<>();
        for(int i = 1, j = 1, s = 1; i < target; i ++){
    
    
            while(s < target){
    
    
                j ++;
                s += j;
            }
            if(s == target && j - i >= 1){
    
    
                int[] one = new int[j - i + 1];
                for(int k = i; k <= j; k ++)
                    one[k - i] = k;
                re.add(one);
            }
            s -= i;
        }
        return re.toArray(new int[re.size()][]);
    }
}
//C++版
class Solution {
    
    
public:
    vector<vector<int> > FindContinuousSequence(int sum) {
    
    
        //单调性
        //i j  sum   i+1 j sum-i
        //i变大 j变大
        vector<vector<int> > res;
        for(int i = 1, j = 1, s = 1; i < sum; i ++)
        {
    
    
            while(s < sum) j ++, s += j;
            if(s == sum && j - i > 0)
            {
    
    
                //i j序列压入
                vector<int> line;
                for(int k = i; k <= j; k ++) line.push_back(k);
                res.push_back(line);
            }
            s -= i;
        }
        
        return res;
        
    }
};

和为s的连续正数序列
在这里插入图片描述

//java版
//哈希表
class Solution {
    
    
    public int[] twoSum(int[] nums, int target) {
    
    
                Set<Integer> s = new HashSet<>();
        for (int i=0;i<nums.length;i++){
    
    
            s.add(nums[i]);
        }
        for (int i=0;i<nums.length;i++){
    
    
            if(s.contains(target-nums[i])){
    
    
                return new int[]{
    
    nums[i],target-nums[i]};
            }
        }
        return null;
    }
}

//双指针
class Solution {
    
    
    public int[] twoSum(int[] nums, int target) {
    
    
        //递增
        int i = 0, j = nums.length - 1;
        while(i < j){
    
    
            int s = nums[i] + nums[j];
            if(s < target) i ++;
            else if(s > target) j --;
            else return new int[]{
    
    nums[i], nums[j]};
        }
        return null;
    }
}

//C++版
class Solution {
    
    
public:
    vector<int> FindNumbersWithSum(vector<int> array,int sum) {
    
    

        vector<int> result;
        int length = array.size();
        int start = 0;
        int end = length - 1;
        while (start < end)
        {
    
    
            if (array[start] + array[end] == sum)
            {
    
    
                result.push_back(array[start]);
                result.push_back(array[end]);
                break;
            }
            else if (array[start] + array[end] < sum)
                start++;
            else
                end--;
        }
        return result;

    }
};

58.翻转单词顺序

在这里插入图片描述

//java版
class Solution {
    
    
    public String reverseWords(String s) {
    
    
        s = s.trim();//去除首尾空格
        int j = s.length() - 1, i = j;
        StringBuilder res = new StringBuilder();
        while(i >= 0){
    
    
            while(i >= 0 && s.charAt(i) != ' ') i --;//找到空格
            res.append(s.substring(i + 1, j + 1) + " ");//添加单词
            while(i >= 0 && s.charAt(i) == ' ') i --;//跳过空格
            j = i;
        }
        return res.toString().trim();
    }
}
//C++版
class Solution {
    
    
public:
    string ReverseSentence(string str) {
    
    
        //翻转所有字符
        reverse(str.begin(), str.end());
        //翻转单个单词
        for(int i = 0; i < str.size(); i ++)
        {
    
    
            int j = i;
            while(j < str.size() && str[j] != ' ') j ++;
            //翻转单个单词
            reverse(str.begin() + i, str.begin() + j);
            i = j;
        }
        
        return str;
    }
};

左旋转字符串
在这里插入图片描述

//java版
class Solution {
    
    
    public String reverseLeftWords(String s, int n) {
    
    
        return s.substring(n, s.length()) + s.substring(0, n);
    }
}
//C++版
class Solution {
    
    
public:
    string LeftRotateString(string str, int n) {
    
    
        //翻转整个字符串
        reverse(str.begin(), str.end());
        //翻转前半部分
        reverse(str.begin(), str.begin() + str.size() - n);
        //翻转后半部分
        reverse(str.begin() + str.size() - n, str.end());
        
        return str;
    }
};

59.滑动窗口的最大值

在这里插入图片描述

//java版
class Solution {
    
    
    public int[] maxSlidingWindow(int[] nums, int k) {
    
    
        if(nums.length == 0 || k == 0)
            return new int[0];
        int[] res = new int[nums.length-k+1];
        Deque<Integer> q = new LinkedList<>();
        int j=0;
        for(int i=0;i<nums.length;i++){
    
    
            if(q.size()>0 && i-q.peekFirst() >= k)//判断队头是否需要出队
                q.pollFirst();
            while(q.size()>0&&nums[q.peekLast()]<nums[i])//维护队列单调性
                q.pollLast();
            q.add(i);
            if(i >= k-1){
    
    
                res[j++] = (nums[q.peekFirst()]);//取队头作为窗口最大元素
            }
        }
        return res;
    }
}
//C++版
class Solution {
    
    
public:
    vector<int> maxInWindows(const vector<int>& num, unsigned int size)
    {
    
    
        vector<int> res; // num[i]
        //双向队列 pop
        deque<int> q;//保存num 中的index
        for(int i = 0; i < num.size(); i ++)
        {
    
    
            //队头什么时候出队
            while(!q.empty() && i - q.front() >= size) q.pop_front();
            //维护一个队列的单调性
            //4,2,6
            //q 0 1 newindex
            //什么时候pop队尾
            //当新进来的index对应的值比队尾的值>=  队尾pop
            while(!q.empty() && num[i] >= num[q.back()]) q.pop_back();
            
            q.push_back(i);//每次都push  index
            
            //i >= size - 1
            //i从0开始
            if(i >= size - 1) res.push_back(num[q.front()]);
        }
        return res;
    }
};

队列的最大值
在这里插入图片描述

//java版
class MaxQueue {
    
    
    Queue<Integer> que;
    Deque<Integer> deq;//记录最大值
    public MaxQueue() {
    
    
        que = new LinkedList<>();
        deq = new LinkedList<>();
    }
    
    public int max_value() {
    
    
        //取双端队列的队首作为做大值
        return deq.size()> 0   deq.peek() : -1;
    }
    
    public void push_back(int value) {
    
    
        que.add(value);
        while(deq.size() > 0 && deq.peekLast() < value){
    
    
            deq.pollLast();//保证双端队列存的就是最大的值,将队尾小于value的元素全部删除
        }
        deq.add(value);
    }
    
    public int pop_front() {
    
    
        int v = que.size() > 0   que.poll() : -1;
        if(deq.size() > 0 && deq.peekFirst() == v)
            deq.pollFirst();
        
        return v;
    }
}

60.n个骰子的点数

在这里插入图片描述

//java版
class Solution {
    
    
    public double[] twoSum(int n) {
    
    
        //1 1~6   6   6   1 + 5 * 1
        //2 2~12  36  11  1 + 5 * 2
        //3 3~18  6^3 16  1 + 5 * 3
        //4 4~24  6^4 21  1 + 5 * 4
        //n n~n*6
        //方案总数 6^n
        double all = Math.pow(6,n);//方案总数
        //状态数组
        int[][] dp = new int[n + 1][6*n + 1];
        dp[0][0] = 1;
        //dp[i][j]有i个骰子 点数和为j的方案总数
        //先统计每个点数可行方案的数量
        for(int i = 1; i <= n; i ++)//n个骰子
            for(int j = 1; j <= 6 * i; j ++)
                for(int k = 1; k <= Math.min(j, 6); k ++)
                    dp[i][j] += dp[i - 1][j - k];//前i次总和为j的方案总数
        double[] res = new double[1 + 5 * n];
        for(int i = n; i <= n * 6; i ++)
            res[i - n] = dp[n][i] / all;//然后再换成概率
        return res;        
    }
}
//C++版
class Solution {
    
    
public:
    vector<double> twoSum(int n) {
    
    
        //暴力递归
        // vector<int> res;
        // for(int i = n; i <= n * 6; i ++)
        //     res.push_back(dfs(n, i));
        vector<vector<int>> f(n + 1, vector<int>(n * 6 + 1));
        f[0][0] = 1;
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= i * 6; j ++)
                for(int k = 1; k <= min(j, 6); k ++)
                    f[i][j] += f[i - 1][j - k];//前i次总和为j的方案次数
        
        vector<int> res;
        for(int i = n; i <= n * 6; i ++) res.push_back(f[n][i]);
        int sum = 0;
        for(auto x : res)
            sum += x;
        vector<double> out;
        for(auto x : res)
            out.push_back(double(x)/ double(sum));
        return out;
    }
    int dfs(int n, int sum)
    {
    
    
        if(sum < 0) return 0;
        if(n == 0) return !sum;
        
        int res = 0;
        for(int i = 1; i <= 6; i ++)
            res += dfs(n - 1, sum - i);
        return res;
    }
};

猜你喜欢

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