剑指offer(1/2)

只出现一次的数字

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

// 前提知识:
// 异或运算:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。

// n^0 = n;
// n^n = 0;
// n^n^m = n^(n^m) 满***换律
// 所以,我们可以让数组中的每一个数异或一下,最后会得到一个结果ret,就是两个出现一次的数字的异或结果这个结果肯定是由两个不同数字异或而来,因此我们找ret二进制中为1的位置i,因为1一定是由0,1异或而来,因此要求得两个数中,一定有一个数的二进制中的第i个位置为1, 一个为0.

// 如何找到位置i?可用i = ret ^ (-ret)
// 因为计算机用补码存取二进制数,而负数的补码为反码+1,举个例子
// 假如ret = 1110 , -ret = 0010 , 所以 i = 0010
// 所以,再异或一遍即可得到答案。

//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果

public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        int num=0;
        for(int i=0;i<array.length;i++){
            num^=array[i];//所有数异或,结果为不同的两个数字的异或
        }
        int count=0;//标志位,记录num中的第一个1出现的位置
        for(;count<array.length;count++){
            if((num&(1<<count))!=0){
                break;
            }
        }
        num1[0]=0;
        num2[0]=0;
        for(int i=0;i<array.length;i++){
            if((array[i]&(1<<count))==0){//标志位为0的为一组,异或后必得到一个数字(这里注意==的优先级高于&,需在前面加())
                num1[0]^=array[i];
            }else{
                num2[0]^=array[i];//标志位为1的为一组
            }
        }   
    }
}
//哈希表
class Solution {
public:
   void FindNumsAppearOnce(vector<int> data, int* num1, int *num2) {
    unordered_map<int, int> map;
    for (int i = 0; i < data.size(); i++)
        map[data[i]]++;
    vector<int>v;
    for (int i = 0; i < data.size(); i++)
        if (map[data[i]]== 1)
            v.push_back(data[i]);
    *num1 = v[0]; *num2 = v[1];
    }
};

数据流中的中位数

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。


import java.util.PriorityQueue;
import java.util.Comparator;
public class Solution {
    //小顶堆
    private PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
     
    //大顶堆
    private PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(15, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2 - o1;
        }
    });
     
    //记录偶数个还是奇数个
    int count = 0;
    //每次插入小顶堆的是当前大顶堆中最大的数
    //每次插入大顶堆的是当前小顶堆中最小的数
    //这样保证小顶堆中的数永远大于等于大顶堆中的数
    //中位数就可以方便地从两者的根结点中获取了
    public void Insert(Integer num) {
        //个数为偶数的话,则先插入到大顶堆,然后将大顶堆中最大的数插入小顶堆中
        if(count % 2 == 0){
            maxHeap.offer(num);
            int max = maxHeap.poll();
            minHeap.offer(max);
        }else{
            //个数为奇数的话,则先插入到小顶堆,然后将小顶堆中最小的数插入大顶堆中
            minHeap.offer(num);
            int min = minHeap.poll();
            maxHeap.offer(min);
        }
        count++;
    }
    public Double GetMedian() {
        //当前为偶数个,则取小顶堆和大顶堆的堆顶元素求平均
        if(count % 2 == 0){
            return new Double(minHeap.peek() + maxHeap.peek())/2;
        }else{
            //当前为奇数个,则直接从小顶堆中取元素即可
            return new Double(minHeap.peek());
        }
    }
}
class Solution {
private:
		vector<int> min;
		vector<int> max;
public:
    	void Insert(int num)
    	{
    	   if(((min.size()+max.size())&1)==0)//偶数时 ,放入最小堆 
		   {
		   	  if(max.size()>0 && num<max[0])
		   	  {
		   	  	// push_heap (_First, _Last),要先在容器中加入数据,再调用push_heap ()
		   	  	 max.push_back(num);//先将元素压入容器
		   	  	 push_heap(max.begin(),max.end(),less<int>());//调整最大堆 
				 num=max[0];//取出最大堆的最大值 
				 //pop_heap(_First, _Last),要先调用pop_heap()再在容器中删除数据
				 pop_heap(max.begin(),max.end(),less<int>());//删除最大堆的最大值 
				 max.pop_back(); //在容器中删除 
			  }
			  min.push_back(num);//压入最小堆 
			  push_heap(min.begin(),min.end(),greater<int>());//调整最小堆 
		   }
		   else//奇数时候,放入最大堆
		   {
		   	  if(min.size()>0 && num>min[0])
		   	  {
		   	  	// push_heap (_First, _Last),要先在容器中加入数据,再调用push_heap ()
			     min.push_back(num);//先压入最小堆 
				 push_heap(min.begin(),min.end(),greater<int>());//调整最小堆 
				 num=min[0];//得到最小堆的最小值(堆顶) 
				 //pop_heap(_First, _Last),要先调用pop_heap()再在容器中删除数据
				 pop_heap(min.begin(),min.end(),greater<int>());//删除最小堆的最大值 
				 min.pop_back(); //在容器中删除 
			  }
		   	  max.push_back(num);//压入数字 
		   	  push_heap(max.begin(),max.end(),less<int>());//调整最大堆 
		   }	
		}
		/*获取中位数*/		
		double GetMedian()
		{
			int size=min.size()+max.size();
			if(size<=0) //没有元素,抛出异常 
			    return 0;//throw exception("No numbers are available");
			if((size&1)==0)//偶数时,去平均 
			    return ((double)(max[0]+min[0])/2);
			else//奇数,去最小堆,因为最小堆数据保持和最大堆一样多,或者比最大堆多1个 
			    return min[0];
		}
};

复制复杂链表

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
*/
//下面那段代码思维太混乱了,大家不要参考,如果要用map解决此题,看这段代码就好
import java.util.*;
public class Solution {
    public RandomListNode Clone(RandomListNode pHead)
    {
        HashMap<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>();
        RandomListNode p = pHead;
        //第一次遍历 新建立节点
        while(p != null){
            RandomListNode newNode = new RandomListNode(p.label);
            map.put(p, newNode);
            p = p.next;
        }
        //第二次遍历 赋值映射关系
        p = pHead;
        while(p != null){
            RandomListNode node = map.get(p);
            node.next = (p.next == null)?null: map.get(p.next);
            node.random = (p.random == null)?null: map.get(p.random);
            p = p.next;
        }
        //最后的返回值
        return map.get(pHead);

    }
}
/*
struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
*/
/*
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        if(pHead=NULL) return pHead;//如果是空,那么的话返回本身也就是返回空
        RandomListNode *cur=pHead;//用结构体建造两个指针一个当前节点,一个临时存下一个
        RandomListNode *nex=NULL;
        //复制元素放入链表中
        while(cur){
            RandomListNode * clone= new RandomListNode(cur->label);
            nex=cur->next;//临时存当前A的下一个即B
            cur->next=clone;//当前A指向复制的A1
            clone->next=nex;//A1的下一个指向B
            cur=nex;//将复制的插入到了链表中,那么A跳到下一个即B
        }
        //重新遍历,复制原链表的随机指针
        cur=pHead;
        while(cur){
            nex=cur->next;
            nex->random = cur->random ? cur->random->next : cur->random;
            /*
            if(cur->random)//不能反回节点引用,报错
                nex->random=cur->random->next;
            else
                nex->random=cur->random;
                
            cur=nex->next;
        }
        //重新遍历拆分链表
        cur= pHead;
        RandomListNode *newhead=cur->next;
        while(cur){
            nex=cur->next;
            cur->next=nex->next;
            cur=nex->next;
            nex->next=cur ? cur->next:cur;
        }
        return newhead;
    }
};
*/
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        if(!pHead)
            return nullptr;
        RandomListNode* tmp = pHead;
        while(tmp){
            RandomListNode* nd = new RandomListNode(tmp -> label);
            RandomListNode* nt = tmp -> next;
            tmp -> next = nd;
            nd -> next = nt;
            tmp = nt;
        }
        for(RandomListNode* nh = pHead; nh; nh = nh -> next -> next){
            if(nh -> random)
                nh -> next -> random = nh -> random -> next;
        }
        RandomListNode* dummy = new RandomListNode(0);
        RandomListNode* nx = dummy;
        for(RandomListNode* nd = pHead; nd; ){
            nx -> next = nd -> next;
            nx = nx -> next;
            nd -> next = nx -> next;
            nd = nd -> next;
        }
        return dummy -> next;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值