16.实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。
不得使用库函数,同时不需要考虑大数问题。
示例 1:
输入:x = 2.00000, n = 10
输出:1024.00000
示例 2:输入:x = 2.10000, n = 3
输出:9.26100
示例 3:输入:x = 2.00000, n = -2
输出:0.25000
解释:2-2 = 1/22 = 1/4 = 0.25
提示:
-100.0 < x < 100.0
-231 <= n <= 231-1
-104 <= xn <= 104
先来一个经典超时
class Solution {
public double myPow(double x, int n) {
double a=x;
long b=n;
if(a==0){return 0;}
if(b<0){
a=(double)(1/a);
b=-b;
}
double res=1.0;
while(b>0){
res*=a;
b--;
}
return res;
}
}
现在时间复杂度是n,快速幂法可以降低到logn;(自己想到的,嘿嘿)
class Solution {
public double myPow(double x, int n) {
if(x == 0) return 0;
long b = n;
double res = 1.0;
if(b < 0) {
x = 1 / x;
b = -b;
}
while(b > 0) {
if(b%2==1){
res*=x;
b--;
}else{
x*=x;
b=b/2;
}
}
return res;
}
}
7.输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
示例 1:
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
示例 2:Input: preorder = [-1], inorder = [-1]
Output: [-1]
限制:
0 <= 节点个数 <= 5000
想法是递归
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
//递归一下
//前序应该是根左右,中序应该是左根右
if(preorder.length==0){return null;}
TreeNode root=new TreeNode(preorder[0]);
//将inorder按preorder的值分成左右两个子数组,分别是左子树的中序遍历和右子树的中序遍历
//通过inorder得到的数组长度分割inorder,分别为左子树的前序遍历和右子树的前序遍历
int k=0;
for(int i=0;i
很慢。
。
怎么优化一下呢?检索很慢,考虑哈希映射,快速定位根节点。
(get比遍历快)
class Solution {
private Map indexMap;
public TreeNode myBuildTree(int[] preorder, int[] inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) {
if (preorder_left > preorder_right) {
return null;
}
int preorder_root = preorder_left;
// 在中序遍历中定位根节点
int inorder_root = indexMap.get(preorder[preorder_root]);
TreeNode root = new TreeNode(preorder[preorder_root]);
int size_left_subtree = inorder_root - inorder_left;
root.left = myBuildTree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1);
root.right = myBuildTree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right);
return root;
}
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n = preorder.length;
indexMap = new HashMap();
for (int i = 0; i < n; i++) {
indexMap.put(inorder[i], i);
}
return myBuildTree(preorder, inorder, 0, n - 1, 0, n - 1);
}
}
答案的迭代法:
关于前序遍历数组里两个邻近的数,a和b,有三种情况:(判断方法是前序和中序数组比较)
1.b是a的左儿子(前存储ab,中存储ba)
2.a没有左儿子
2.1a有右儿子———b是a的右儿子(前中都存储的ab)
2.2a没有右儿子——b是a的某个祖先的右儿子(前存储ab,中存储a一堆祖先b)
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder.length == 0)
return null;
Stack s = new Stack<>();
TreeNode root = new TreeNode(preorder[0]);
TreeNode cur = root;
//前序的第一个已经拿到了,接下来一个一个拿
for (int i = 1, j = 0; i < preorder.length; i++) {
//符合ab ba,直接a的左指向b
if (cur.val != inorder[j]) {
cur.left = new TreeNode(preorder[i]);
s.push(cur);
cur = cur.left;
} else {
//不符合即a没有左儿子,移动一下j,如果b是a的右儿子,直接指向,否则去找祖先,让祖先的右指向b
j++;
//s存储祖先,找到b的祖先,没找到就继续j++;
while (!s.empty() && s.peek().val == inorder[j]) {
cur = s.pop();
j++;
}
cur = cur.right = new TreeNode(preorder[i]);
}
}
return root;
}
}
17.输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。
比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
示例 1:
输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]
说明:
用返回一个整数列表来代替打印
n 为正整数
那必然是阴间遍历啊
class Solution {
public int[] printNumbers(int n) {
int length=(int)Math.pow(10,n);
int[] res=new int[length-1];
for(int i=0;i
假设考虑大数溢出?-转成字符串类型。
18.给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
注意:此题对比原题有改动
示例 1:
输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:输入: head = [4,5,1,9], val = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
说明:
题目保证链表中节点的值互不相同
若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点
class Solution {
public ListNode deleteNode(ListNode head, int val) {
ListNode temp=head;
if(temp.val==val){
head=head.next;
}
while(temp!=null){
if(temp.next!=null&&temp.next.val==val){
temp.next=temp.next.next;
break;
}else{
temp=temp.next;
}
}
return head;
}
}
22.输入一个链表,输出该链表中倒数第k个节点。
为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。
这个链表的倒数第 3 个节点是值为 4 的节点。
示例:
给定一个链表: 1->2->3->4->5, 和 k = 2.
返回链表 4->5.
1.顺序查找
2.双指针间隔k
3.反转链表求第k个
4.栈
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
//栈搞一哈
Stack stack=new Stack<>();
ListNode temp=head;
while(temp!=null){
stack.push(temp);
temp=temp.next;
}
for(int i=1;i
21.输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数在数组的前半部分,所有偶数在数组的后半部分。
示例:
输入:nums = [1,2,3,4]
输出:[1,3,2,4]
注:[3,1,2,4] 也是正确的答案之一。
提示:
0 <= nums.length <= 50000
0 <= nums[i] <= 10000
双指针搞一哈
class Solution {
public int[] exchange(int[] nums) {
//双指针
int length=nums.length;
if(length==0){
return nums;
}
int right=length-1;
int left=0;
while(left=right){
//已经排好了
return nums;
}
//交换
int temp=nums[left];
nums[left]=nums[right];
nums[right]=temp;
}
return nums;
}
}
25.输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
示例1:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
限制:0 <= 链表长度 <= 1000
1.递归法
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//递归法搞一哈
if(l1==null){
return l2;
}else if(l2==null){
return l1;
}else if(l1.val<=l2.val){
l1.next=mergeTwoLists(l1.next,l2);
return l1;
}else{
l2.next=mergeTwoLists(l1,l2.next);
return l2;
}
}
}
2.双指针
42.输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。
求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
提示:
1 <= arr.length <= 10^5
-100 <= arr[i] <= 100
改变数组
class Solution {
public int maxSubArray(int[] nums) {
//改变数组
//每次存储与前一个数的和、当前数中的最大值。
int max=nums[0];
for(int i=1;imax){
max=nums[i];
}
}
return max;
}
}
动态规划
class Solution {
public int maxSubArray(int[] nums) {
//动态规划一下子
int pre=0;
int max=nums[0];
for(int i=0;i
答案有个分治算法,整挺好。
class Solution {
public class Status {
public int lSum, rSum, mSum, iSum;
public Status(int lSum, int rSum, int mSum, int iSum) {
this.lSum = lSum;
this.rSum = rSum;
this.mSum = mSum;
this.iSum = iSum;
}
}
public int maxSubArray(int[] nums) {
return getInfo(nums, 0, nums.length - 1).mSum;
}
public Status getInfo(int[] a, int l, int r) {
if (l == r) {
return new Status(a[l], a[l], a[l], a[l]);
}
int m = (l + r) >> 1;
Status lSub = getInfo(a, l, m);
Status rSub = getInfo(a, m + 1, r);
return pushUp(lSub, rSub);
}
public Status pushUp(Status l, Status r) {
int iSum = l.iSum + r.iSum;
int lSum = Math.max(l.lSum, l.iSum + r.lSum);
int rSum = Math.max(r.rSum, r.iSum + l.rSum);
int mSum = Math.max(Math.max(l.mSum, r.mSum), l.rSum + r.lSum);
return new Status(lSum, rSum, mSum, iSum);
}
}
39.数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2
限制:
1 <= 数组长度 <= 50000
1.排序
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length/2];
}
}
不改变数组:
2.hashMap
3.摩尔投票
class Solution {
public int majorityElement(int[] nums) {
//投票
int number=0;
int count=0;
for(int i=0;i
4.分治
class Solution {
public int majorityElement(int[] nums) {
//分治
int k=merge(nums,0,nums.length-1);
return k;
}
//计算从left到right目标数出现的次数
public int countLeftNumber(int[] nums,int target,int left,int right){
int count=0;
for(int i=left;i<=right;i++){
if(nums[i]==target){
count++;
}
}
return count;
}
//分而治之
public int merge(int[] nums,int left,int right){
if(left==right){
return nums[left];
}
int mid=(left+right)/2;
int leftNumber=merge(nums,left,mid);
int rightNumber=merge(nums,mid+1,right);
if(leftNumber==rightNumber){
return leftNumber;
}
//计算左众数多还是右众数多,谁多听谁的
int l=countLeftNumber(nums,leftNumber,left,right);
int r=countLeftNumber(nums,rightNumber,left,right);
return l>r?leftNumber:rightNumber;
}
}
5.随机挑选一个数判断是不是众数
40.输入整数数组 arr ,找出其中最小的 k 个数。
例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:输入:arr = [0,1,2,1], k = 1
输出:[0]
限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
无脑排序
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
Arrays.sort(arr);
int[] res=new int[k];
for(int i=0;i
答案自建堆:用一个大根堆维护数组的前k个小值,然后从k+1开始遍历,如果遍历到的数比堆顶的数小,就d出堆顶的数,插入当前数,最后将大根堆里的数存入数组返回。
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
//堆排
int[] res=new int[k];
if(k==0){
return res;
}
//创建一个优先队列-难点
PriorityQueue queue = new PriorityQueue(
//匿名内部类
new Comparator() {
public int compare(Integer num1, Integer num2) {
return num2 - num1;
}
});
for(int i=0;i
快排:
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
//快排
quick(arr,0,arr.length-1);
int[] r=new int[k];
for(int i=0;ipivot){
r--;
}
//直到左指针大于等于右指针才结束
if(l>=r){
break;
}
temp=arr[l];
arr[l]=arr[r];
arr[r]=temp;
//说明pivot已经被换到左边了,所以右指针要左移
if(arr[l]==pivot){
r--;
}
//说明此时,pivot已经被换到右边了,所以左指针要继续右移
if(arr[r]==pivot){
l++;
}
}
//如果左边等于右边,可能会锁死循环
if (r==l){
r--;
l++;
}
//
if(leftl){
quick(arr,l,right);
}
}
}
答案给的快排就是比尚硅谷这个快:9ms和2ms的区别
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
randomizedSelected(arr, 0, arr.length - 1, k);
int[] vec = new int[k];
for (int i = 0; i < k; ++i) {
vec[i] = arr[i];
}
return vec;
}
private void randomizedSelected(int[] arr, int l, int r, int k) {
if (l >= r) {
return;
}
int pos = randomizedPartition(arr, l, r);
int num = pos - l + 1;
if (k == num) {
return;
} else if (k < num) {
randomizedSelected(arr, l, pos - 1, k);
} else {
randomizedSelected(arr, pos + 1, r, k - num);
}
}
// 基于随机的划分
private int randomizedPartition(int[] nums, int l, int r) {
int i = new Random().nextInt(r - l + 1) + l;
swap(nums, r, i);
return partition(nums, l, r);
}
private int partition(int[] nums, int l, int r) {
int pivot = nums[r];
int i = l - 1;
for (int j = l; j <= r - 1; ++j) {
if (nums[j] <= pivot) {
i = i + 1;
swap(nums, i, j);
}
}
swap(nums, i + 1, r);
return i + 1;
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
答案二叉搜索树:
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if (k == 0 || arr.length == 0) {
return new int[0];
}
TreeMap map = new TreeMap<>();
int cnt = 0;
for (int num: arr) {
if (cnt < k) {
map.put(num, map.getOrDefault(num, 0) + 1);
cnt++;
continue;
}
Map.Entry entry = map.lastEntry();
if (entry.getKey() > num) {
map.put(num, map.getOrDefault(num, 0) + 1);
if (entry.getValue() == 1) {
map.pollLastEntry();
} else {
map.put(entry.getKey(), entry.getValue() - 1);
}
}
}
int[] res = new int[k];
int idx = 0;
for (Map.Entry entry: map.entrySet()) {
int freq = entry.getValue();
while (freq-- > 0) {
res[idx++] = entry.getKey();
}
}
return res;
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)