剑指offer(day1)

 

一、写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

先看看十进制数的运算,比如6和7 不计进位得到3,计算进位得到10. 10+3 即为结果。

  1. 两个数异或:相当于每一位相加,而不考虑进位;
  2. 两个数相与,并左移一位:相当于求得进位;
  3. 上述两步的结果相加

6--->110             7---->111

110^111为001 即1

(110&111)<<1为12

1+12=13即为结果

 public int Add(int num1,int num2) {
    while( num2!=0 ){
        int sum = num1 ^ num2;
        int carray = (num1 & num2) << 1;
        num1 = sum;
        num2 = carray;
    }
    return num1;
}

二、找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

输入: [2, 3, 1, 0, 2, 5, 3] 输出:2 或 3

法1

class Solution {
    public int findRepeatNumber(int[] nums) {
        Set<Integer> set= new HashSet<Integer>();
        int res=-1;
        for(int num:nums)
            if(!set.add(num)){ //add失败返回fasle 即找到了重复元素
                res=num;
                break;
            }
        return res;
    }
}

解题方法利用了hashet集合中没有重复的值的特点。遍历nums,将元素添加到hashset中,直到某次失败,则说明找到了重复的数

法二

巧妙利用数组下标来匹配对应的元素,从前往后遍历数组,每个元素都要求下标与元素的值一一对应,如果在调换位置的过程中发现该位置的元素与别的位置的元素是相同的,那么就说明该数字重复,直接返回该数字

class Solution {
   public  int findRepeatNumber(int[] nums){
    for (int i = 0; i < nums.length; i++){
        //将数字与下标对应起来
        while (nums[i] != i){
            int temp = nums[i];
            //如果准备移动的数字已经等于对应位置上的数字则说明数字重复
            if(temp == nums[temp]) return temp;
            nums[i] = nums[temp];
            nums[temp] = temp;
        }
    }
    return Integer.MAX_VALUE;
    }
}

例如arr=[2,3,1,0,2,5,3]

当i=0,因arr[i]!=i,令temp=arr[i],此时temp为2。接着判断temp==arr[temp],2不等于1

所以交换。arr[i]=arr[temp],arr[temp]=temp

此时arr为[1,3,2,0,2,5,3]

当i=1,因arr[i]!=i,令temp=arr[i],此时temp为3。接着判断temp==arr[temp],3不等于0

所以交换。arr[i]=arr[temp],arr[temp]=temp

此时arr为[1,0,2,3,2,5,3]

当i=2,因arr[i]!=i, 2==2  while循环结束

当i=3,因arr[i]!=i, 3==3 while循环结束

当i=4,因arr[i]!=i,即2!=4,令temp=arr[i],此时temp为2。接着判断temp==arr[temp],2==2

所以return 2;

此时说明2重复了,程序结束

三、链表中倒数第k个节点

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。

 给定一个链表: 1->2->3->4->5, 和 k = 2. 返回链表 4->5.

经典双指针,快指针先走k步,接着快慢指针一起每次走一步,直到快指针后继为空,此时慢指针所指的元素为导数第k个

Picture0.png

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        ListNode q=head,s=head;
        for(int i=0;i<k;i++){q=q.next;}
        while(q!=null){
            q=q.next;
            s=s.next;
        }
        return s;
    }
}

四、删除链表的节点

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。

返回删除后的链表的头节点。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode deleteNode(ListNode head, int val) {
        if(head.val == val) return head.next;
        ListNode pre = head, cur = head.next;
        while(cur != null && cur.val != val) {
            pre = cur;
            cur = cur.next;
        }
        if(cur != null) pre.next = cur.next;
        return head;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值