文章目录
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;
}
};