算法及思路

7.用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
思路:一个栈压入元素,而另一个栈作为缓冲.

  • 当插入时,直接插入 stack1;
  • 当弹出时,当 stack2 不为空,弹出 stack2 栈顶元素,如果 stack2 为空,将 stack1 中的全部数逐个出栈入栈 stack2,再弹出 stack2 栈顶元素。
    解题技巧:出栈时,先把stack2中元素按顺序出栈,然后再把stack1中所有元素倒序进入stack2.
import java.util.Stack;
public class Solution {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
 
    public void push(int node) {
        stack1.push(node);
    }
 
    public int pop() throws Exception{
    	if (stack1.isEmpty() && stack2.isEmpty()) {
			throw new Exception("栈为空!");
		}
        if (stack2.size() <= 0) {
            while (stack1.size() != 0) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }
}

10.输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
思路:a&(a-1)的结果会将a最右边的1变为0,直到a = 0。如果a为正数,还可以先将a&1 != 0,然后右移1位

public int NumberOf1(int n) {
	int count = 0;
	while (n != 0) {
		count++;
		n = (n-1) & n;
	} 
	return count;
}

12.打印从1到最大的n位数
思路:当输入的n很大的时候,我们求最大的n位数是不是用整型(int)或者长整型(long long)都会溢出?也就是说我们需要考虑大数问题。

  1. 使用字符串或数组表示数,
  2. 数组第0位表示n位数的最高位,递归调用,给数组每个元素赋值,直到循环到数组最后位;
  3. 开始打印数组,打印数组时;
  4. 打印数组时,从开头第一个不为0的元素开始打印。
    第一次 0 0 0 … 0 0
public void printToMaxOfNDigits(int n) {
    int[] array=new int[n];
    if(n <= 0)
        return;
    printArray(array, 0);
}
private void printArray(int[] array,int n) {
    for(int i = 0; i < 10; i++) {
        if(n != array.length) {
            array[n] = i;
            //递归赋值,直到最后一位开始循环打印
            printArray(array, n+1);
        } else {
            boolean isFirstNo0 = false;
            for(int j = 0; j < array.length; j++) {
                if(array[j] != 0) {
                    System.out.print(array[j]);
                    if(!isFirstNo0)
                        isFirstNo0 = true;
                } else {
                    if(isFirstNo0)
                        System.out.print(array[j]);
                }
            }
            System.out.println();
            return ;
        }
    }
}

13.O(1)时间删除链表节点
思路:不需要找到将要删除节点的前一个节点;将要删除节点的下一个节点的值赋给要删除的节点,然后指向下下一个节点。
14.输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
思路:每次只和前面一个数交换位置。或者利用辅助数组。
只需要找到并向前调整奇数,偶数相对就实现调整。因为前面数组是已经调整好的,所以把奇数前面的所有偶数向后移动一位,直到遇到一个奇数停止。

public void reOrderArray(int [] array) {
    if(array == null)
         return ;
     for(int i = 1; i < array.length; i++){
         int temp = array[i];
         int j = i - 1;
         if(array[i] % 2 != 0){//奇数
             while(j >= 0){
                 if(array[j] % 2 != 0){
            //遇到奇数,说明前面已经全部是奇数,不需要往前判断
                     break;
                 }else{//遇到偶数,需要把所有偶数向后移动
                     int t = array[j+1];
                     array[j+1] = array[j];
                     array[j] = t;
                     j--;
                 }
             }
         }
         array[j+1] = temp;
     }
 }

15.输入一个链表,输出该链表中倒数第k个结点。
扩展题:找中间节点,使用两个指针,一个走一步,一个走两步。找到中间节点
思路:定义一快一慢两个指针,快指针走K步,然后慢指针开始走,快指针到尾时,慢指针就找到了倒数第K个
节点。
16.输入一个链表,反转链表后,输出链表的所有元素。
思路:定义两个指针,反向输出。把旧链表节点按顺序一个一个插入新链表的头部,一个指针(temp)指向新链表的头部,一个指针(P)指向旧链表的头结点的下一位,把旧链表动态头结点(head)插入到新链表的头部
扩展题:输出反转后链表的头节点,定义三个指针反向输出。

public ListNode ReverseList(ListNode head) {
    if (head == null) {
        return null;
    } 
    ListNode temp = null;
    while(head != null) {
        ListNode p = head.next;
        head.next = temp;
        temp = head;
        head = p;
    } 
    return temp;
}

16.输入一个链表,反转链表后,输出链表的所有元素。
思路:将链表节点,采用头部插入法插入,生成的新链表即为反转链表。


    public ListNode reverseList(ListNode head){
        if(head == null){
            return  null;
        }
        ListNode newHead = null;
        ListNode temp = null;
        while (head != null){
            temp = head.next;
            head.next = newHead;
            newHead = head;
            head = temp;
        }
        return newHead;
    }

找两个链表公共节点
什么是公共节点,并不是两个节点的值相同就是公共节点。
而是在第一链表和第二链表中都存在一个节点,该节点往后的子链表在两个链表中是相同的。
在这里插入图片描述
方法一:
如果我们从两个链表的尾部开始往前比较,那么最后一个相同的节点就是我们要找的节点。分别将两个链表的节点放入两个栈中,这样栈顶就是两个链表的尾节点,比较两个栈顶节点是否相同,如果相同,将栈顶弹出比较下一个栈顶,直到找到最后一个相同的栈顶。时间复杂度O(m + n)。
方法二:
先获得两个链表的长度,然后在较长的链表上先走若干步(两链表长度之差),接着同时在两个链表上遍历,找到的第一个相同的节点就是他们的第一个公共节点。时间复杂度O(m + n)。
方法三:
用两个指针同时分别扫描”两个链表“,当指针到达null时从另一个链表开始扫描,最终两个指针到达公共结点走的步数是一样。
(m+n-x),其中m,n分别为两个链表长度,x为链表的公共长度。

public ListNode findFirstCommonNode(ListNode pHead1, ListNode pHead2){
        if(pHead1 == null || pHead2 == null){
            return null;
        }
        ListNode temp1 = pHead1;
        ListNode temp2 = pHead2;
        while (temp1 != temp2){
            temp1 = (temp1 == null? pHead2 : temp1.next);
            temp2 = (temp2 == null? pHead1 : temp2.next);
        }
        return temp1;
    }

30.求一个数组的top k个最大元素。
思路,用长度为K的数组表示小顶堆,取数组前K个元素构成一个小顶堆,剩下数组元素与小顶堆的根比较,如果比根大,则替换根元素,并进行堆排序。
堆排序思路:

  1. K个数组构建小顶堆:从下层第一个非叶子开始,与左右子节点比较,把左右子节点中的最小那个元素替换父节点。
  2. 堆顶元素替换后排序:比较根节点与左右子节点,选择最小那个元素和父节点替换位置,同时对替换位置后的左(右)子节点进行排序。

    public int[] sort(int[] input, int k){
        if(input == null || input.length == 0){
            return null;
        }
        int length = input.length;
        if(length <= k){
            return input;
        }
        int[] result = new int[k];

        //构建长度为k的堆
        for(int i = 0; i< k; i++){
            result[i] = input[i];
        }
        //从最后一个非叶子节点开始进行排序
        for(int i = k/2 -1; i >= 0; i--){
            minHeap(result, i);
        }
        //数组后面元素与小顶堆比较,如果大于则替换堆顶元素
        for (int i = k; i< length; i++){
            if(input[i] > result[0]){
                result[0] = input[i];
                minHeap(result, 0);
            }

        }
        return result;
    }

//i表示待排序的元素的索引下标
    public void minHeap(int[] array, int i){
        int left = 2*i + 1;
        int right = left + 1;
        int min = i;
        int length = array.length;
        if(left < length && array[left] < array[min]){
            min = left;
        }
        if(right < length && array[right] < array[min]){
            min = right;
        }
        if(min != i){
            int temp = array[i];
            array[i] = array[min];
            array[min] = temp;
            minHeap(array, min);
        }
    }
    

31.求连续子数组(包含负数)的最大和
思路:如果连续子数组和小于0,则将最大和置为当前元素值。


public int findGreatestSumOfSubArray(int[] array){
        if(array == null || array.length == 0){
            return 0;
        }
        int currentSum = array[0];
        int greatest = currentSum;
        int length = array.length;
        for (int i = 1; i < length; i++){
            if(currentSum < 0){
                currentSum = array[i];
            }else {
                currentSum += array[i];
            }
            if(greatest < currentSum){
                greatest = currentSum;
            }
        }
        return greatest;
}

给定一棵二叉搜索树,请找出其中的第k小的结点。
思路:二叉搜索树左节点> 父节点 > 右节点。 因此找最新K节点先遍历左子树,再遍历根节点,然后遍历右子树,采用中序遍历方式即可。用栈保存父节点,然后遍历左子树。

链接:https://www.nowcoder.com/questionTerminal/ef068f602dde4d28aab2b210e859150a?answerType=1&f=discussion
来源:牛客网

import java.util.Stack;
public class Solution {
    TreeNode KthNode(TreeNode pRoot, int k)
    {
        if(pRoot == null || k <= 0){
            return null;
        }
        Stack<TreeNode> stack = new Stack<>(); //建立栈
        TreeNode cur = pRoot;
        //while 部分为中序遍历
        while(!stack.isEmpty() || cur != null){ 
            if(cur != null){
                stack.push(cur); //当前节点不为null,应该寻找左儿子
                cur = cur.left;
            }else{
                cur = stack.pop();//当前节点null则弹出栈内元素,相当于按顺序输出最小值。
                if(--k == 0){ //计数器功能
                    return cur;
                }
                cur = cur.right;
            }
        }
        return null;
    }
}

40.一个整型数组里除了两个数字之外,其他的数字都出现了两次。找出这两个只出现一次的数字。
思路:两个相同的数字异或运算之后为0;将所有元素做异或运算,结果为那两个只出现一次的数字做异或运算;找出计算结果1出现的位置,在这个位置这两个数一个为0,一个为1;把数组分为两部分,在这个位置为0的一组,为1的一组,分别做异或运算,两组结果即为这两个数字(0^a = a)。

public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
	if (array == null)
	return;
	num1[0] = 0;
	num2[0] = 0;
	int number = array[0];
	for (int i = 1; i < array.length; i++)
	number ^= array[i];
	// 异或后的数1出现在第几位
	int index = 0;
	while ((number & 1) == 0) {
		number = number >> 1;
		index++;
	}
	for (int i = 0; i < array.length; i++) {
		// 判断第index位是不是0
		boolean isBit = ((array[i] >> index) & 1) == 0;
		if (isBit) {
			num1[0] ^= array[i];
		} else {
			num2[0] ^= array[i];
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值