1.最小栈
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。
class MinStack {
Stack<Integer> stack;
Stack<Integer> minStack;
/** initialize your data structure here. */
public MinStack() {
stack=new Stack<>();
minStack=new Stack<>();
}
public void push(int val) {
if(stack.isEmpty()){
minStack.push(val);
}else{
if(val<minStack.peek()){ //minStack每次入栈的时候需要和栈顶做比较
minStack.push(val);
}else{
minStack.push(minStack.peek());
}
}
stack.push(val);
}
public void pop() {
stack.pop();
minStack.pop();
}
public int top() {
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}
https://leetcode-cn.com/problems/min-stack/solution/zui-xiao-zhan-by-leetcode-solution/
2.多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
(1)map统计
(2)投票法
思路:如果我们把众数记为 +1,把其他数记为−1,将它们全部加起来,显然和大于 0,从结果本身我们可以看出众数比其他数多。(要这么想,即使众数是第一个,那也能将其他的数都抵消掉,更不用说若第一个不是众数,那么最后留下的也是众数)
int count=0;
Integer res=null;
for(int num : nums){
if(count==0){
res=num;
}
if(num==res){
count++;
}else{
count--;
}
}
return res;
(3)排序
Arrays.sort(nums);
return nums[nums.length/2];
3.回文链表
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
(1)复制到数组中,两个指针一个放到0,一个放到size-1,一起往中间走
class Solution {
public boolean isPalindrome(ListNode head) {
List<Integer> vals = new ArrayList<Integer>();
// 将链表的值复制到数组中
ListNode currentNode = head;
while (currentNode != null) {
vals.add(currentNode.val);
currentNode = currentNode.next;
}
// 使用双指针判断是否回文
int front = 0;
int back = vals.size() - 1;
while (front < back) {
if (!vals.get(front).equals(vals.get(back))) {
return false;
}
front++;
back--;
}
return true;
}
}
(2)以下5个步骤:
找到前半部分链表的尾节点。
反转后半部分链表。
判断是否回文。
恢复链表。(本题可以不用恢复)
返回结果。
class Solution {
public boolean isPalindrome(ListNode head) {
if (head == null) {
return true;
}
// 找到前半部分链表的尾节点并反转后半部分链表
ListNode firstHalfEnd = endOfFirstHalf(head);
ListNode secondHalfStart = reverseList(firstHalfEnd.next);
// 判断是否回文
ListNode p1 = head;
ListNode p2 = secondHalfStart;
boolean result = true;
while (result && p2 != null) {
if (p1.val != p2.val) {
result = false;
}
p1 = p1.next;
p2 = p2.next;
}
// 还原链表并返回结果
firstHalfEnd.next = reverseList(secondHalfStart);
return result;
}
private ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
private ListNode endOfFirstHalf(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
}
4.比特位计数
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
示例 1:
输入: 2
输出: [0,1,1]
示例 2:
输入: 5
输出: [0,1,1,2,1,2]
(1)暴力解
public int[] countBits(int n) {
int [] res=new int[n+1];
int num=0;
int count=0;
for(int i=0;i<=n;i++){ //遍历每个数
num=i;
count=0;
while(num!=0){ //对1进行计数
if((num&1)==1){
count++;
}
res[i]=count;
num=num>>1;
}
}
return res;
}
(2)找规律
0~3 是两位,分别是00,01,10,11,然后 4 到 7 是三位,分别是100,101,110,111,这不就是前面多了个 1 嘛! 直接相加就可以了。。后面的以此类推即可
public int[] countBits(int n) {
if(n==0){
return new int[]{0};
}
int [] res=new int[n+1];
res[0]=0;
res[1]=1;
int mul=2; //初始值为2
for(int i=2;i<=n;i++){
if(i==mul){ //该数是2的某次方,1的个数必为1
res[i]=1;
mul*=2;
}else{
res[i]=1+res[i-mul/2]; //注意mul要除2
}
}
return res;
}
5.二叉树的直径
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
示例 :
给定二叉树
1
/ \
2 3
/ \
4 5
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。
思路:再计算树的高度的时候顺便计算了最大直径
class Solution {
int max=0;
public int diameterOfBinaryTree(TreeNode root) {
dfs(root);
return max;
}
public int dfs(TreeNode root){
if(root==null){
return 0;
}
int left=dfs(root.left);
int right=dfs(root.right);
max=Math.max(max,left+right);
return Math.max(left,right)+1;
}
}