guys.
I have an algo with a good timing, i should change it to get better time, but i have no any idea.
Can u help me?
Here is time:
real 0m0.164s
user 0m0.021s
sys 0m0.010s
Here is algo:
def algo2(A, B):
x=0
y=0
for a in A:
m=0
for b in B:
if a == b:
m += 1
if m>y:
x = a
y = m
return x;
Here is arrays for algo:
A = [1,2,3,4,5,6,7,8,9,0]
B = [1,2,3,4,5,6,4,7,8,9,0]
Your algorithm is O(n*m). If the arrays are always sorted, you can do a straight merge (O(n+m)), as below. (Note that the code is not python ... I think you can get the idea and translate it)
ixA = 0
ixB = 0
maxVal = 0
maxCount = 0
workingVal = A[ixA]
workingCount = 0
while (ixA < A.length and ixB < B.length)
{
if (workingVal == B[ixB])
{
workingCount += 1
}
else if (workingCount > maxCount)
{
maxCount = workingCount
maxVal = workingVal
workingCount = 0
ixA += 1
workingVal = A[ixA]
}
ixB += 1
}
// have to check the last one
if (workingCount > maxCount)
{
maxCount = workingCount
maxVal = workingVal
}
If the arrays aren't sorted, you can sort them first, then do the merge. That will be O(m log m) + O(n log n) + O(m+n). That's still better than your O(m*n).
Related
I am trying to make an algorithm, of Θ( n² ).
It accepts an unsorted array of n elements, and an integer z,
and has to return 3 indices of 3 different elements a,b,c ; so a+b+c = z.
(return NILL if no such integers were found)
I tried to sort the array first, in two ways, and then to search the sorted array.
but since I need a specific running time for the rest of the algorithm, I am getting lost.
Is there any way to do it without sorting? (I guess it does have to be sorted) either with or without sorting would be good.
example:
for this array : 1, 3, 4, 2, 6, 7, 9 and the integer 6
It has to return: 0, 1, 3
because ( 1+3+2 = 6)
Algorithm
Sort - O(nlogn)
for i=0... n-1 - O(1) assigning value to i
new_z = z-array[i] this value is updated each iteration. Now, search for new_z using two pointers, at begin (index 0) and end (index n-1) If sum (array[ptr_begin] + array[ptr_ens]) is greater then new_z, subtract 1 from the pointer at top. If smaller, add 1 to begin pointer. Otherwise return i, current positions of end and begin. - O(n)
jump to step 2 - O(1)
Steps 2, 3 and 4 cost O(n^2). Overall, O(n^2)
C++ code
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> vec = {3, 1, 4, 2, 9, 7, 6};
std::sort(vec.begin(), vec.end());
int z = 6;
int no_success = 1;
//std::for_each(vec.begin(), vec.end(), [](auto const &it) { std::cout << it << std::endl;});
for (int i = 0; i < vec.size() && no_success; i++)
{
int begin_ptr = 0;
int end_ptr = vec.size()-1;
int new_z = z-vec[i];
while (end_ptr > begin_ptr)
{
if(begin_ptr == i)
begin_ptr++;
if (end_ptr == i)
end_ptr--;
if ((vec[begin_ptr] + vec[end_ptr]) > new_z)
end_ptr--;
else if ((vec[begin_ptr] + vec[end_ptr]) < new_z)
begin_ptr++;
else {
std::cout << "indices are: " << end_ptr << ", " << begin_ptr << ", " << i << std::endl;
no_success = 0;
break;
}
}
}
return 0;
}
Beware, result is the sorted indices. You can maintain the original array, and then search for the values corresponding to the sorted array. (3 times O(n))
The solution for the 3 elements which sum to a value (say v) can be done in O(n^2), where n is the length of the array, as follows:
Sort the given array. [ O(nlogn) ]
Fix the first element , say e1. (iterating from i = 0 to n - 1)
Now we have to find the sum of 2 elements sum to a value (v - e1) in range from i + 1 to n - 1. We can solve this sub-problem in O(n) time complexity using two pointers where left pointer will be pointing at i + 1 and right pointer will be pointing at n - 1 at the beginning. Now we will move our pointers either from left or right depending upon the total current sum is greater than or less than required sum.
So, overall time complexity of the solution will be O(n ^ 2).
Update:
I attached solution in c++ for the reference: (also, added comments to explain time complexity).
vector<int> sumOfthreeElements(vector<int>& ar, int v) {
sort(ar.begin(), ar.end());
int n = ar.size();
for(int i = 0; i < n - 2 ; ++i){ //outer loop runs `n` times
//for every outer loop inner loops runs upto `n` times
//therefore, overall time complexity is O(n^2).
int lo = i + 1;
int hi = n - 1;
int required_sum = v - ar[i];
while(lo < hi) {
int current_sum = ar[lo] + ar[hi];
if(current_sum == required_sum) {
return {i, lo, hi};
} else if(current_sum > required_sum){
hi--;
}else lo++;
}
}
return {};
}
I guess this is similar to LeetCode 15 and 16:
LeetCode 16
Python
class Solution:
def threeSumClosest(self, nums, target):
nums.sort()
closest = nums[0] + nums[1] + nums[2]
for i in range(len(nums) - 2):
j = -~i
k = len(nums) - 1
while j < k:
summation = nums[i] + nums[j] + nums[k]
if summation == target:
return summation
if abs(summation - target) < abs(closest - target):
closest = summation
if summation < target:
j += 1
elif summation > target:
k -= 1
return closest
Java
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int closest = nums[0] + nums[nums.length >> 1] + nums[nums.length - 1];
for (int first = 0; first < nums.length - 2; first++) {
int second = -~first;
int third = nums.length - 1;
while (second < third) {
int sum = nums[first] + nums[second] + nums[third];
if (sum > target)
third--;
else
second++;
if (Math.abs(sum - target) < Math.abs(closest - target))
closest = sum;
}
}
return closest;
}
}
LeetCode 15
Python
class Solution:
def threeSum(self, nums):
res = []
nums.sort()
for i in range(len(nums) - 2):
if i > 0 and nums[i] == nums[i - 1]:
continue
lo, hi = -~i, len(nums) - 1
while lo < hi:
tsum = nums[i] + nums[lo] + nums[hi]
if tsum < 0:
lo += 1
if tsum > 0:
hi -= 1
if tsum == 0:
res.append((nums[i], nums[lo], nums[hi]))
while lo < hi and nums[lo] == nums[-~lo]:
lo += 1
while lo < hi and nums[hi] == nums[hi - 1]:
hi -= 1
lo += 1
hi -= 1
return res
Java
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> res = new LinkedList<>();
for (int i = 0; i < nums.length - 2; i++) {
if (i == 0 || (i > 0 && nums[i] != nums[i - 1])) {
int lo = -~i, hi = nums.length - 1, sum = 0 - nums[i];
while (lo < hi) {
if (nums[lo] + nums[hi] == sum) {
res.add(Arrays.asList(nums[i], nums[lo], nums[hi]));
while (lo < hi && nums[lo] == nums[-~lo])
lo++;
while (lo < hi && nums[hi] == nums[hi - 1])
hi--;
lo++;
hi--;
} else if (nums[lo] + nums[hi] < sum) {
lo++;
} else {
hi--;
}
}
}
}
return res;
}
}
Reference
You can see the explanations in the following links:
LeetCode 15 - Discussion Board
LeetCode 16 - Discussion Board
LeetCode 15 - Solution
You can use something like:
def find_3sum_restr(items, z):
# : find possible items to consider -- O(n)
candidates = []
min_item = items[0]
for i, item in enumerate(items):
if item < z:
candidates.append(i)
if item < min_item:
min_item = item
# : find possible couples to consider -- O(n²)
candidates2 = []
for k, i in enumerate(candidates):
for j in candidates[k:]:
if items[i] + items[j] <= z - min_item:
candidates2.append([i, j])
# : find the matching items -- O(n³)
for i, j in candidates2:
for k in candidates:
if items[i] + items[j] + items[k] == z:
return i, j, k
This O(n + n² + n³), hence O(n³).
While this is reasonably fast for randomly distributed inputs (perhaps O(n²)?), unfortunately, in the worst case (e.g. for an array of all ones, with a z > 3), this is no better than the naive approach:
def find_3sum_naive(items, z):
n = len(items)
for i in range(n):
for j in range(i, n):
for k in range(j, n):
if items[i] + items[j] + items[k] == z:
return i, j, k
This is a question from one of the old exams from algorithms and data structure that I recently came upon. I'm having a hard time understanding the solution.
I need to find big-O, big-ϴ and big-Ω bounds of a function:
void recursion(int n) {
int i;
if (n == 0) {
return;
}
for (i = 0; i < n; i++) {
recursion(i);
}
}
The solution is 2^n for all three and I can't understand why. I've tried writing things down and I can't even get close to the solution. I would appreciate if anyone would explain where the 2^n comes from here.
Let's look at a simpler recursion which is known to be O(2^n)
void fib(int n) {
if (n < 3) {
return 1;
} else {
return fib(n - 1) + fib(n - 2);
}
}
Here you can see, for the non-trivial case of n > 2, this will result in 2^(n-2) calls to itself. For example, if n = 5:
n = 5
n = 4
n = 3
n = 2
n = 1
n = 2
n = 3
n = 2
n = 1
There are 8 (2^3) recursive calls, because each call with n > 2 spawns two more recursive calls, so fib(n+1) has twice as many recursive calls as fib(n).
So for your example:
n = 3
n = 2
n = 1
n = 0
n = 0
n = 1
n = 0
n = 0
so we get 7 recursive calls when n = 3
for n = 4
n = 4
n = 3
n = 2
n = 1
n = 0
n = 0
n = 1
n = 0
n = 0
n = 2
n = 1
n = 0
n = 0
n = 1
n = 0
n = 0
Here, we have 15 calls. Looking at the execution tree above, you can see that recusrsion(4) is basically recursion(3) + recursion(3) + 1
n = 4
n = 3 // + 1
n = 2 //
n = 1 //
n = 0 // recursion(3)
n = 0 //
n = 1 //
n = 0 //
n = 0 //
n = 2 //
n = 1 //
n = 0 // recursion(3)
n = 0 //
n = 1 //
n = 0 //
n = 0 //
So in general, recursion(n + 1) will have one more recursive calls than 2 * recursion(n)....which is basically doubling for every +1 to n....which is O(2^n)
Let's denote the total runtime as f(n). Due to the loop in the function the f(n) is actually a sum of f(i) for i between 0 and n-1. That's a sum of n items. Let's try to simplify the expression. A standard trick in such situations is to find a complimentary equation. Let's see what is the value of f(n-1). Similary to the previous case, it's a sum of f(i) for i between 0 and n-2. So now we have 2 equations:
f(n)=f(1)+...+f(n-1)
f(n-1)=f(1)+...+f(n-2)
Let's subtract second from the first:
f(n)-f(n-1)=f(n-1)
--> f(n)=2f(n-1)
Now this is a homogeneous linear recurrence relation with constant coefficients.
The solution is immediate (see the link for more details):
f(n)=f(1)*2n=2n
Since this smells like a homework question, this answer is incomplete by design.
The usual trick behind these kind of problems is to create a recurrence equation. That is, the time complexity of recursion(k+1) is somehow related to the complexity of recursion(k). Just writing down the recurrence itself is not sufficient to prove the complexity, you have to demonstrate why the recurrence is true. But, for 2n, this suggests that recursion(k+1) takes twice as long as recursion(k).
Let T(k) denote the time complexity of recursion(k). Since recursion(0) returns immediately, let T(0) = 1. For k > 0, given the iterative implementation of recursion Thus You can inductively prove that T(k) = 2k.
r(n) = r(n-1)+r(n-2)+...+r(0) // n calls.
r(n-1) = r(n-2)+r(n-3)+...+r(0) // n-1 calls.
r(n-2) = r(n-3)+r(n-4)+...+r(0) // n-2 calls.
.
.
.
r(1) = r(0) // 1 call.
r(0) = return; // 0 call.
So,
r(n) = r(n-1)+r(n-2)+...+r(0) // n calls.
= 2 * (r(n-2)+...+r(0)) // 2 * (n - 1) calls.
= 2 * ( 2 * (r(n-3)+...+r(0)) ) // 2 * 2 * (n - 2) calls.
.
.
.
This follows that =>
2^(n-1) * (n - (n-1))
And that would be
2^n calls...
For a given b and N and a range of a say (0...n),
I need to find ans(0...n-1)
where,
ans[i] = no of a's for which pow(a, b)modN == i
What I am searching here is a possible repetition in pow(a,b)modN for a range of a, to reduce computation time.
Example:-
if b = 2 N = 3 and n = 5
for a in (0...4):
A[pow(a,b)modN]++;
so that would be
pow(0,2)mod3 = 0
pow(1,2)mod3 = 1
pow(2,2)mod3 = 1
pow(3,2)mod3 = 0
pow(4,2)mod3 = 1
so the final results would be:
ans[0] = 2 // no of times we have found 0 as answer .
ans[1] = 3
...
Your algorithm have a complexity of O(n).
Meaning it take a lot of time when n gets bigger.
You could have the same result with an algorithm O(N).
As N << n it will reduce your computation time.
Firts, two math facts :
pow(a,b) modulo N == pow (a modulo N,b) modulo N
and
if (i < n modulo N)
ans[i] = (n div N) + 1
else if (i < N)
ans[i] = (n div N)
else
ans[i] = 0
So a solution to your problem is to fill your result array with the following loop :
int nModN = n % N;
int nDivN = n / N;
for (int i = 0; i < N; i++)
{
if (i < nModN)
ans[pow(i,b) % N] += nDivN + 1;
else
ans[pow(i,b) % N] += nDivN;
}
You could calculate pow for primes only, and use pow(a*b,n) == pow(a,n)*pow(b,n).
So if pow(2,2) mod 3 == 1 and pow(3,2) mod 3 == 2, then pow(6,2) mod 3 == 2.
Suppose I have an array of M elements, all numbers, negative or positive or zero.
Can anyone suggest an algorithm to select N elements from the array, such that the sum of these N elements is the smallest possible positive number?
Take this array for example:
-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200
Now I have to select any 5 elements such that their sum is the smallest possible positive number.
Formulation
For i = 1, ..., M:
Let a_i be the ith number in your list of candidates
Let x_i denote whether the ith number is included in your set of N chosen numbers
Then you want to solve the following integer programming problem.
minimize: sum(a_i * x_i)
with respect to: x_i
subject to:
(1) sum(a_i * x_i) >= 0
(2) sum(x_i) = N
(3) x_i in {0, 1}
You can apply an integer program solver "out of the box" to this problem to find the optimal solution or a suboptimal solution with controllable precision.
Resources
Integer programming
Explanation of branch-and-bound integer program solver
If you want to find the best possible solution, you can simply use brute force ie. try all posible combinations of fiwe numbers.
Something like this very quick and dirty algorithm:
public List<Integer> findLeastPositivSum(List<Integer> numbers) {
List<Integer> result;
Integer resultSum;
List<Integer> subresult, subresult2, subresult3, subresult4, subresult5;
for (int i = 0; i < numbers.size() - 4; i++) {
subresult = new ArrayList<Integer>();
subresult.add(numbers.get(i));
for (int j = i + 1; j < numbers.size() - 3; j++) {
subresult2 = new ArrayList<Integer>(subresult);
subresult2.add(j);
for (int k = j + 1; k < numbers.size() - 2; k++) {
subresult3 = new ArrayList<Integer>(subresult2);
subresult3.add(k);
for (int l = k + 1; l < numbers.size() - 1; l++) {
subresult4 = new ArrayList<Integer>(subresult3);
subresult4.add(k);
for (int m = l + 1; m < numbers.size(); m++) {
subresult5 = new ArrayList<Integer>(subresult4);
subresult5.add(k);
Integer subresultSum = sum(subresult5);
if (subresultSum > 0) {
if (result == null || resultSum > subresultSum) {
result = subresult;
}
}
}
}
}
}
}
return result;
}
public Integer sum(List<Integer> list) {
Integer result = 0;
for (Integer integer : list) {
result += integer;
}
return result;
}
This is really quick and dirty algorithm, it can be done more elegantly. I can provide cleaner algorithm e.g. using recursion.
It can be also further optimized. E.g. you can remove similar numbers from input list as first step.
Let initial array be shorted already, or i guess this will work even when it isnt shorted..
N -> Length of array
M -> Element req.
R[] -> Answer
TEMP[] -> For calculations
minSum -> minSum
A[] -> Initial input
All above variables are globally defined
int find(int A[],int start,int left)
{
if(left=0)
{
//sum elements in TEMP[] and save it as curSum
if(curSum<minSum)
{
minSum=curSum;
//assign elements from TEMP[] to R[] (i.e. our answer)
}
}
for(i=start;i<=(N-left);i++)
{
if(left==M)
curSum=0;
TEMP[left-1]=A[i];
find(A[],i+1,left-1);
}
}
// Made it in hurry so maybe some error would be existing..
Working solution on ideone :
http://ideone.com/YN8PeW
I suppose Kadane’s Algorithm would do the trick, although it is for the maximum sum but I have also implemented it to find the minimum sum, though can't find the code right now.
Here's something sub optimal in Haskell, which (as with many of my ideas) could probably be further and better optimized. It goes something like this:
Sort the array (I got interesting results by trying both ascending and descending)
B N = first N elements of the array
B (i), for i > N = best candidate; where (assuming integers) if they are both less than 1, the candidates are compared by the absolute value of their sums; if they are both 1 or greater, by their sums; and if only one candidate is greater than 0 then that candidate is chosen. If a candidate's sum is 1, return that candidate as the answer. The candidates are:
B (i-1), B (i-1)[2,3,4..N] ++ array [i], B (i-1)[1,3,4..N] ++ array [i]...B (i-1)[1,2..N-1] ++ array [i]
B (i-2)[2,3,4..N] ++ array [i], B (i-2)[1,3,4..N] ++ array [i]...B (i-2)[1,2..N-1] ++ array [i]
...
B (N)[2,3,4..N] ++ array [i], B (N)[1,3,4..N] ++ array [i]...B (N)[1,2..N-1] ++ array [i]
Note that for the part of the array where the numbers are negative (in the case of ascending sort) or positive (in the case of descending sort), step 3 can be done immediately without calculations.
Output:
*Main> least 5 "desc" [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200]
(10,[-1000,600,300,100,10])
(0.02 secs, 1106836 bytes)
*Main> least 5 "asc" [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200]
(50,[300,100,-200,-100,-50])
(0.02 secs, 1097492 bytes)
*Main> main -- 10000 random numbers ranging from -100000 to 100000
(1,[-106,4,-40,74,69])
(1.77 secs, 108964888 bytes)
Code:
import Data.Map (fromList, insert, (!))
import Data.List (minimumBy,tails,sort)
import Control.Monad.Random hiding (fromList)
array = [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200]
least n rev arr = comb (fromList listStart) [fst (last listStart) + 1..m]
where
m = length arr
r = if rev == "asc" then False else True
sorted = (if r then reverse else id) (sort arr)
listStart = if null lStart
then [(n,(sum $ take n sorted,take n sorted))]
else lStart
lStart = zip [n..]
. takeWhile (all (if r then (>0) else (<0)) . snd)
. foldr (\a b -> let c = take n (drop a sorted) in (sum c,c) : b) []
$ [0..]
s = fromList (zip [1..] sorted)
comb list [] = list ! m
comb list (i:is)
| fst (list ! (i-1)) == 1 = list ! (i-1)
| otherwise = comb updatedMap is
where updatedMap = insert i bestCandidate list
bestCandidate = comb' (list!(i - 1)) [i - 1,i - 2..n] where
comb' best [] = best
comb' best (j:js)
| fst best == 1 = best
| otherwise =
let s' = map (\x -> (sum x,x))
. (take n . map (take (n - 1)) . tails . cycle)
$ snd (list!j)
t = s!i
candidate = minimumBy compare' (map (add t) s')
in comb' (minimumBy compare' [candidate,best]) js
add x y#(a,b) = (x + a,x:b)
compare' a#(a',_) b#(b',_)
| a' < 1 = if b' < 1 then compare (abs a') (abs b') else GT
| otherwise = if b' < 1 then LT else compare a' b'
rnd :: (RandomGen g) => Rand g Int
rnd = getRandomR (-100000,100000)
main = do
values <- evalRandIO (sequence (replicate (10000) rnd))
putStrLn (show $ least 5 "desc" values)
Assumption: M is the original array
Pesudocode
S = sort(M);
R = [];
sum = 0;
for(i=0, i < length(S); i++){
sum = sum + S[i];
if(sum < 1){
R.push(S[i]);
}else{
return R;
}
}
I was trying to solve Project Euler problem number 7 using scala 2.8
First solution implemented by me takes ~8 seconds
def problem_7:Int = {
var num = 17;
var primes = new ArrayBuffer[Int]();
primes += 2
primes += 3
primes += 5
primes += 7
primes += 11
primes += 13
while (primes.size < 10001){
if (isPrime(num, primes)) primes += num
if (isPrime(num+2, primes)) primes += num+2
num += 6
}
return primes.last;
}
def isPrime(num:Int, primes:ArrayBuffer[Int]):Boolean = {
// if n == 2 return false;
// if n == 3 return false;
var r = Math.sqrt(num)
for (i <- primes){
if(i <= r ){
if (num % i == 0) return false;
}
}
return true;
}
Later I tried the same problem without storing prime numbers in array buffer. This take .118 seconds.
def problem_7_alt:Int = {
var limit = 10001;
var count = 6;
var num:Int = 17;
while(count < limit){
if (isPrime2(num)) count += 1;
if (isPrime2(num+2)) count += 1;
num += 6;
}
return num;
}
def isPrime2(n:Int):Boolean = {
// if n == 2 return false;
// if n == 3 return false;
var r = Math.sqrt(n)
var f = 5;
while (f <= r){
if (n % f == 0) {
return false;
} else if (n % (f+2) == 0) {
return false;
}
f += 6;
}
return true;
}
I tried using various mutable array/list implementations in Scala but was not able to make solution one faster. I do not think that storing Int in a array of size 10001 can make program slow. Is there some better way to use lists/arrays in scala?
The problem here is that ArrayBuffer is parameterized, so what it really stores are references to Object. Any reference to an Int is automatically boxed and unboxed as needed, which makes it very slow. It is incredibly slow with Scala 2.7, which uses a Java primitive to do that, which does it very slowly. Scala 2.8 takes another approach, making it faster. But any boxing/unboxing will slow you down. Furthermore, you are first looking up the ArrayBuffer in the heap, and then looking up again for java.lang.Integer containing the Int -- two memory accesses, which makes it way slower than your other solution.
When Scala collections become specialized, it should be plenty faster. Whether it should be enough to beat your second version or not, I don't know.
Now, what you may do to get around that is to use Array instead. Because Java's Array are not erased, you avoid the boxing/unboxing.
Also, when you use for-comprehensions, your code is effectively stored in a method which is called for each element. So you are also making many method calls, which is another reason this is slower. Alas, someone wrote a plugin for Scala which optimizes at least one case of for-comprehensions to avoid that.
Using Array should make it work in about zero seconds with the right algorithm. This, for example, takes about 7 milliseconds on my system:
class Primes(bufsize: Int) {
var n = 1
val pbuf = new Array[Int](bufsize max 1)
pbuf(0) = 2
def isPrime(num: Int): Boolean = {
var i = 0
while (i < n && pbuf(i)*pbuf(i) <= num) {
if (num % pbuf(i) == 0) return false
i += 1
}
if (pbuf(i)*pbuf(i) < num) {
i = pbuf(i)
while (i*i <= num) {
if (num % i == 0) return false
i += 2
}
}
return true;
}
def fillBuf {
var i = 3
n = 1
while (n < bufsize) {
if (isPrime(i)) { pbuf(n) = i; n += 1 }
i += 2
}
}
def lastPrime = { if (n<bufsize) fillBuf ; pbuf(pbuf.length-1) }
}
object Primes {
def timedGet(num: Int) = {
val t0 = System.nanoTime
val p = (new Primes(num)).lastPrime
val t1 = System.nanoTime
(p , (t1-t0)*1e-9)
}
}
Result (on second call; first has some overhead):
scala> Primes.timedGet(10001)
res1: (Int, Double) = (104743,0.00683394)
I think you have to think out of the box :)
Because the problem is manageable, you can use Sieve of Eratosthenes to solve it very efficiently.
Here's a recursive solution (using the isPrime function from your first solution). It seems to be good Scala style to prefer immutability (i.e. to try not to use vars) so I've done that here (in fact there are no vars or vals!). I don't have a Scala installation here though so can't tell if this is actually any quicker!
def problem_7:Int = {
def isPrime_(n: Int) = (n % 6 == 1 || n % 6 == 5) && isPrime(n)
def process(n: Int, acc: List[Int]): Int = {
if (acc.size == 10001) acc.head
else process(n+1, if isPrime_(n) n :: acc else acc)
}
process(1, Nil)
}