剑指offer 基础算法练习(二)

1.二进制中1的个数

题目:输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。

思路:如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。 
举例: 
一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000. 
也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。

function NumberOf1(n)
{
    // write code here
    var count = 0 
    while (n) {
        count++
        n = (n -1) & n
    }
    return count
}

补充:

                例:求-5的补码。

        -        5对应正数5(00000101)→所有位取反(11111010)→加1(11111011)


2.数值的整数次方

题目:给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

保证base和exponent不同时为0。不得使用库函数,同时不需要考虑大数问题,也不用考虑小数点后面0的位数。

思路:幂数相乘

function Power(base, exponent)
{
    // write code here
    if(exponent < 0) {
        if (base == 0) {
            return false
        } else {
            return 1/Power(base, -exponent)
        }
    }else if(exponent == 0) {
        return 1
    } else {
        if (base == 0) {
            return false
        } else {
            return Power(base, exponent-1) * base
        }
    }
}


3.调整数组顺序使奇数位于偶数前面

题目:

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变

思路:主要使用数组的两种方法,数组遍历方法forEach(),数组合并方法concat()

先循环遍历数组,判断奇偶,再分别放入数组,最后进行数组合并

function reOrderArray( array ) {
    // write code here
    var oddArr = []
    var evenArr = []
    array.forEach(function(item,index) {
        if (item % 2 ==0) {
            evenArr.push(item)
        } else {
            oddArr.push(item)
        }
    });
    return oddArr.concat(evenArr)
}


4.链表中倒数第K个节点

题目:输入一个链表,输出一个链表,该输出链表包含原链表中从倒数第k个结点至尾节点的全部节点。

如果该链表长度小于k,请返回一个长度为 0 的链表

思路:先定义两个指针,先让第一个指针和第二个指针都指向头结点,然后再让第一个指正走(k-1)步,到达第k个节点。然后两个指针同时往后移动,当第一个指针到达末尾的时候,第二个指针所在位置就是倒数第k个节点了

function FindKthToTail( pHead ,  k ) {
    // write code here
    if(pHead == null || k <=0) {
        return false
    }
    var p1 = pHead
    var p2 = pHead
    for(var i = 1; i < k; i++) {
        if(!p1.next) {
            return 0
        }else {
            p1 = p1.next
        }
    }
    while(p1.next) {
        p1 = p1.next
        p2 = p2.next
    }
    return p2
}


5.反转链表

题目:输入一个链表,反转链表后,输出新链表的表头。

思路:【图文解析】反转一个单链表

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function ReverseList(pHead)
{
    // write code here
    if(pHead == null) {
        return false
    }
    var p1 = pHead
    var p2 = null ,temp = null
    while(p1) {
        temp = p1.next
        p1.next = p2
        p2 = p1
        p1 = temp
    }
    return p2
}


 6.合并两个排序的链表

题目:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

思路:用递归思想,依次将两个链表的每个元素递归对比后实现

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function Merge(pHead1, pHead2)
{
    // write code here
    if(pHead1 == null) {
        return pHead2
    } else if(pHead2 == null) {
        return pHead1
    }
    var p1 = pHead1, p2 = pHead2
    var newHead = null
    
        if(p1.val > p2.val) {
            newHead = p2
            newHead.next = Merge(p1,p2.next)
        }else {
            newHead = p1
            newHead.next = Merge(p1.next,p2)
        }
        return newHead
}

7.二叉树的镜像

题目:操作给定的二叉树,将其变换为源二叉树的镜像。

 思路:判断树是否为空,然后交换左右子树,最后递归交换左右子树

/*
 * function TreeNode(x) {
 *   this.val = x;
 *   this.left = null;
 *   this.right = null;
 * }
*/
function Mirror( pRoot ) {
    // write code here
    if(pRoot === null) {
        return pRoot
    }
    
    var temp = null
    temp = pRoot.left
    pRoot.left = pRoot.right
    pRoot.right = temp
    
    Mirror(pRoot.left)
    Mirror(pRoot.right)
    
    return pRoot
}

 8.包含min函数的栈

题目定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数,并且调用 min函数、push函数 及 pop函数 的时间复杂度都是 O(1)

push(value):将value压入栈中

pop():弹出栈顶元素

top():获取栈顶元素

min():获取栈中最小元素

思路:JS中数组底层是基于栈实现,因此本题目可根据此属性直接实现,但是注意此题的空值判断

var stack = []
function push(node)
{
    // write code here
    stack.push(node)
}
function pop()
{
    // write code here
    return stack.length == 0? null :stack.pop()
}
function top()
{
    // write code here
    return stack.length == 0? null :stack[stack.length-1]
}
function min()
{
    // write code here
    return stack.length == 0? null :Math.min.apply(null,stack)
}

9.栈的压入、弹出序列

题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

思路:

借用一个辅助的栈,遍历压栈顺序,先讲第一个放入栈中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。 
举例: 
入栈1,2,3,4,5 
出栈4,5,3,2,1 
首先1入辅助栈,此时栈顶1≠4,继续入栈2 
此时栈顶2≠4,继续入栈3 
此时栈顶3≠4,继续入栈4 
此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3 
此时栈顶3≠5,继续入栈5 
此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3 
…. 
依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。

 

function IsPopOrder(pushV, popV)
{
    // write code here
    var arr = []
    for (var i = 0; i < pushV.length; i++) {
        arr.push(pushV[i])
        while(arr.length > 0) {
          if(arr[arr.length-1] == popV[0]) {
             arr.pop()
             popV.shift()
           } else {
               break
           }
        }
    }
    return arr.length == 0
}

10.二叉搜索树与双向链表

题目:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值